@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,1456 @@
|
|
|
1
|
+
import { Context, Effect, Layer, Schema } from "effect";
|
|
2
|
+
import { captureGitTreeSnapshotV1, readGitTreeFileV1 } from "../../adapters/git-task-history.js";
|
|
3
|
+
import { RepositoryFoundryError } from "../../errors.js";
|
|
4
|
+
import { repositoryFoundryRoleOutputCeilingV1 } from "../../repository-foundry-plan-protocol.js";
|
|
5
|
+
import { parseRepositorySpecificationContractFactsProposalV1, REPOSITORY_SPECIFICATION_CONTRACT_FACTS_MAXIMUM_QUESTIONS, renderRepositorySpecificationContractFactV1, RepositorySpecificationContractFactClarificationV1, RepositorySpecificationContractFactReviewV1, RepositorySpecificationContractFactsProposalV1, repositorySpecificationContractFactsPacketV1, repositorySpecificationContractFactsScopeV1 } from "../../repository-specification-contract-facts-protocol.js";
|
|
6
|
+
import { RepositorySpecificationBehaviorCoverageV1, RepositorySpecificationCritiqueAxisV1, RepositorySpecificationDimensionFitV1, RepositorySpecificationReferenceCompatibilityV1, RepositorySpecificationReferenceScopeV1 } from "../../repository-specification-critique-protocol.js";
|
|
7
|
+
import { RepositoryFoundryLanguageModel } from "../language-model/service.js";
|
|
8
|
+
import { critiqueRepositoryTaskSpecificationV1 } from "../specification-critic/service.js";
|
|
9
|
+
const RepositoryAnalysisOutput = Schema.Struct({
|
|
10
|
+
summary: Schema.String,
|
|
11
|
+
userObservableBehaviors: Schema.Array(Schema.String),
|
|
12
|
+
constraints: Schema.Array(Schema.String),
|
|
13
|
+
risks: Schema.Array(Schema.String),
|
|
14
|
+
relevantPaths: Schema.Array(Schema.String),
|
|
15
|
+
referenceScope: Schema.optionalKey(RepositorySpecificationReferenceScopeV1)
|
|
16
|
+
});
|
|
17
|
+
const RepositorySpecificationOutput = Schema.Struct({
|
|
18
|
+
requestText: Schema.String,
|
|
19
|
+
constraints: Schema.Array(Schema.String)
|
|
20
|
+
});
|
|
21
|
+
const RepositorySpecificationReviewOutput = Schema.Struct({
|
|
22
|
+
verdict: Schema.Literals(["sufficient", "insufficient"]),
|
|
23
|
+
detail: Schema.String,
|
|
24
|
+
criticalBehaviorCoverage: Schema.Array(RepositorySpecificationBehaviorCoverageV1),
|
|
25
|
+
dimensionFit: Schema.optionalKey(RepositorySpecificationDimensionFitV1),
|
|
26
|
+
referenceCompatibility: Schema.optionalKey(RepositorySpecificationReferenceCompatibilityV1),
|
|
27
|
+
findings: Schema.Array(Schema.Struct({
|
|
28
|
+
axis: RepositorySpecificationCritiqueAxisV1,
|
|
29
|
+
severity: Schema.Literals(["blocker", "warning"]),
|
|
30
|
+
detail: Schema.String
|
|
31
|
+
}))
|
|
32
|
+
});
|
|
33
|
+
// These schemas are selected only by the immutable facts marker. The legacy
|
|
34
|
+
// schemas, prompts, operation IDs, and serialized inputs above remain unchanged.
|
|
35
|
+
const RepositoryContractFactsAnalysisOutput = Schema.Struct({
|
|
36
|
+
summary: Schema.String,
|
|
37
|
+
userObservableBehaviors: Schema.Array(Schema.String),
|
|
38
|
+
constraints: Schema.Array(Schema.String),
|
|
39
|
+
risks: Schema.Array(Schema.String),
|
|
40
|
+
relevantPaths: Schema.Array(Schema.String),
|
|
41
|
+
referenceScope: RepositorySpecificationReferenceScopeV1,
|
|
42
|
+
contractFacts: RepositorySpecificationContractFactsProposalV1
|
|
43
|
+
}).annotate({ parseOptions: { onExcessProperty: "error" } });
|
|
44
|
+
const RepositoryContractFactsReviewOutput = Schema.Struct({
|
|
45
|
+
verdict: Schema.Literals(["sufficient", "insufficient"]),
|
|
46
|
+
detail: Schema.String,
|
|
47
|
+
criticalBehaviorCoverage: Schema.Array(RepositorySpecificationBehaviorCoverageV1),
|
|
48
|
+
dimensionFit: Schema.optionalKey(RepositorySpecificationDimensionFitV1),
|
|
49
|
+
referenceCompatibility: Schema.optionalKey(RepositorySpecificationReferenceCompatibilityV1),
|
|
50
|
+
findings: Schema.Array(Schema.Struct({
|
|
51
|
+
axis: RepositorySpecificationCritiqueAxisV1,
|
|
52
|
+
severity: Schema.Literals(["blocker", "warning"]),
|
|
53
|
+
detail: Schema.String
|
|
54
|
+
})),
|
|
55
|
+
contractFactReview: RepositorySpecificationContractFactReviewV1
|
|
56
|
+
}).annotate({ parseOptions: { onExcessProperty: "error" } });
|
|
57
|
+
const REFERENCE_ANALYST_INSTRUCTIONS = `This historical benchmark has private, complete pinned before/after
|
|
58
|
+
implementation and historical-test evidence. Treat commit subjects and mechanically inferred targetBehavior
|
|
59
|
+
as candidate scope, not authoritative specifications. Identify the actual observable change and the boundaries
|
|
60
|
+
the reference preserves. In particular, a broad input category must not silently include subcategories that
|
|
61
|
+
the reference explicitly bypasses. Return referenceScope with concrete changed/preserved behavioral clauses,
|
|
62
|
+
each citing valid sourceId and one-based inclusive line ranges in both before and after evidence. Cover every
|
|
63
|
+
critical seed requirement and all relevant eligibility/preservation boundaries. unresolvedQuestions must list
|
|
64
|
+
material questions the evidence cannot settle. Focus on the authentic local delta and its necessary preservation
|
|
65
|
+
boundaries, not a complete audit of every provider, endpoint, or downstream consumer in the repository.
|
|
66
|
+
Distinguish unknowns that affect the required observable change from general integration questions outside
|
|
67
|
+
the visible task. The private compatibility critic will determine whether each question must be answered
|
|
68
|
+
for this task. Do not invent behavior or infer intent merely from a commit subject.
|
|
69
|
+
All summary, behavior, constraint, risk, and scope description strings must be public issue-style language,
|
|
70
|
+
without code, commit IDs, evidence IDs, historical test contents, or implementation instructions. Evidence
|
|
71
|
+
references belong only in referenceScope.clauses[].evidence. Select relevantPaths from pre-change inventory.`;
|
|
72
|
+
const REFERENCE_CRITIC_INSTRUCTIONS = `You also own private reference compatibility. Independently compare
|
|
73
|
+
every visible requirement against the supplied complete pinned after implementation and historical tests,
|
|
74
|
+
including eligibility predicates, bypasses, preservation boundaries, and cross-file integration. The analyst's
|
|
75
|
+
scope and the historical commit subject are hypotheses, never proof. A requirement contradicting the pinned
|
|
76
|
+
reference makes this historical benchmark invalid even if the visible prose is otherwise clear.
|
|
77
|
+
Return referenceCompatibility with exactly one scopeCoverage record per supplied behavioralScope id, and
|
|
78
|
+
concrete after-source line references. Mark contradictory or uncertain coverage as verdict insufficient and
|
|
79
|
+
an unsupported-assumption blocker. Overall compatible is allowed only if ALL visible requirements are
|
|
80
|
+
supported by pinned evidence, every scope clause is correctly represented, and no task-relevant ambiguity is unresolved.
|
|
81
|
+
For each private pendingQuestions entry, return exactly one questionResolutions record with its questionId.
|
|
82
|
+
Use answered only with concrete after-source evidence that settles the question. Use not-required only when
|
|
83
|
+
the question affects NO required behavioralScope clause and NO visible obligation: affectedScopeIds must
|
|
84
|
+
then be empty and visibleScopeExclusion must quote exact visible task text and explain why that bounded
|
|
85
|
+
scope excludes the question. A broad integration unknown is not automatically a task blocker, but never
|
|
86
|
+
excuse uncertainty about eligibility, parsing, errors, preservation, or integration that the visible task
|
|
87
|
+
actually requires. Use unresolved if a task-relevant question cannot be settled; that blocks approval.
|
|
88
|
+
List all affected scope IDs for relevant questions. Question IDs belong only in questionResolutions records,
|
|
89
|
+
never in behavioral review prose. A writer revision changes neither the questions nor their IDs: reassess
|
|
90
|
+
every question against each revised visible task independently.
|
|
91
|
+
Review details and findings are behavioral feedback for a writer: never quote private code, commit IDs,
|
|
92
|
+
evidence IDs, historical test contents, or prescribe an implementation. Evidence IDs belong only in the
|
|
93
|
+
referenceCompatibility evidence records. Do not repair the task or see the other critic's output.`;
|
|
94
|
+
const SPECIFICATION_REVISION_INSTRUCTIONS = `This is a bounded specification revision. Revise your previous
|
|
95
|
+
visible task to resolve every supplied behavioral review finding against the evidence-grounded observable
|
|
96
|
+
scope. Remove unsupported requirements, state eligibility and preservation boundaries precisely, and retain
|
|
97
|
+
all authentic critical behavior. Do not widen scope to fit a dimension. You receive no private after-code or
|
|
98
|
+
reference patch; do not infer or mention one. Return the same requestText and constraints object.`;
|
|
99
|
+
const CONTRACT_FACTS_ANALYST_INSTRUCTIONS = `Return contractFacts version 1 with explicit public behavioral
|
|
100
|
+
facts for every referenceScope clause. Use behavior facts for observable obligations, closed-set facts when a
|
|
101
|
+
complete vocabulary or alternative set matters, and eligibility facts for decisions with distinct inside/outside
|
|
102
|
+
behavior. A closed set must enumerate its COMPLETE task-relevant members, applicability, and outside behavior.
|
|
103
|
+
Do not replace those facts with circular words such as supported, recognized, valid, or appropriate. Each fact
|
|
104
|
+
must cite concrete pinned source evidence. Preserve public protocol literals as behavioral values, but never
|
|
105
|
+
copy private code, internal identifiers, historical test contents, or implementation steps. Describe THIS TASK'S
|
|
106
|
+
local compatibility policy, not a universal provider policy. Do not invent an external capability claim.
|
|
107
|
+
Keep fact and scope IDs short and stable. At most 64 facts, 128 members per closed set, 2000 characters per
|
|
108
|
+
behavior field, 256 characters per member, and 8 evidence references per fact. The full public packet plus
|
|
109
|
+
rendered scope must fit 32768 UTF-8 bytes. Do not truncate a set or silently drop an obligation to fit.
|
|
110
|
+
Your packet is a proposal; independent critics, not your own confidence or citations, determine sufficiency.`;
|
|
111
|
+
const CONTRACT_FACTS_WRITER_INSTRUCTIONS = `The supplied contractFacts packet is a proposed explicit local
|
|
112
|
+
task contract. Its facts will also be rendered by the host into candidate-visible constraints and independently
|
|
113
|
+
reviewed with your text. Write compatible issue-style prose; do not omit, contradict, enlarge, or invent a
|
|
114
|
+
closed set or eligibility rule. Do not call this a universal provider policy. You receive no private evidence,
|
|
115
|
+
clarification records, source IDs, or reference implementation. Return only requestText and constraints.`;
|
|
116
|
+
const CONTRACT_FACTS_REVIEW_INSTRUCTIONS = `Return contractFactReview for the exact supplied contractFacts.digest.
|
|
117
|
+
Return exactly one scopeChecks record per behavioralScope id, listing exactly all supplied fact IDs for that
|
|
118
|
+
scope. Complete is a substantive completeness judgment, not a citation or shape check. Check the actual
|
|
119
|
+
assembled visible task, including its host-rendered constraints. Consider omitted alternatives, applicability,
|
|
120
|
+
eligibility exceptions, outside-set treatment, and necessary preservation behavior, rather than only checking
|
|
121
|
+
the listed examples. Mark missing-facts, contradictory, or uncertain and verdict insufficient when the PACKET
|
|
122
|
+
itself lacks a necessary fact or states an unsupported fact. For every such scope emit a concise structured
|
|
123
|
+
clarificationRequests entry (scopeId, affected factIds, reason, question). Request a complete behavioral rule,
|
|
124
|
+
not another isolated counterexample. Do not infer missing policy from general provider knowledge.
|
|
125
|
+
If the PACKET is adequate but the WRITER'S prose omits or contradicts it, keep the packet check complete,
|
|
126
|
+
reject the visible task in ordinary findings, and do not request analyst clarification merely to rewrite prose.
|
|
127
|
+
Maximum 32 scope checks, 600 characters per check detail, 8 evidence references per check, 16 clarification
|
|
128
|
+
requests, and 800 characters per question. Scope check details and questions must be public behavior prose,
|
|
129
|
+
without private code, source IDs, reference commit IDs, test contents, or implementation instructions.`;
|
|
130
|
+
const CONTRACT_FACTS_REFERENCE_REVIEW_INSTRUCTIONS = `Independently derive the task-relevant distinctions from
|
|
131
|
+
the complete pinned after implementation and declared task domain BEFORE comparing them with the analyst's
|
|
132
|
+
packet. The supplied fact list and apparent completeness are hypotheses, never proof: actively identify an
|
|
133
|
+
omitted member or default branch even when every supplied fact has a plausible citation. For each scopeCheck
|
|
134
|
+
cite after-source evidence that supports both the stated rules and their completeness. Do not approve a false
|
|
135
|
+
fact merely because its citation points to existing lines. Distinguish task-local compatibility from external
|
|
136
|
+
provider correctness. Do not force incidental behavior outside a justified declared task domain into the task.
|
|
137
|
+
You do not see the other current-round critic's response. Reassess every fact after clarification.`;
|
|
138
|
+
const CONTRACT_FACTS_CLARIFICATION_INSTRUCTIONS = `You are the private repository analyst answering bounded
|
|
139
|
+
contract-fact clarification requests. Return version 1, a COMPLETE replacement facts array, and exactly one
|
|
140
|
+
resolutions record per supplied requestId. Preserve all unaffected facts and the original frozen scope IDs.
|
|
141
|
+
The supplied privateContractFacts is the exact private repair base: copy unaffected facts and their evidence
|
|
142
|
+
records unchanged rather than choosing new citations for facts that were not questioned.
|
|
143
|
+
Resolve the whole missing rule or closed set, not just the example named by a critic. Each answered request
|
|
144
|
+
must reference facts in its own scope and concrete evidence already present in privateReferenceEvidence.
|
|
145
|
+
Return unresolved when the pinned evidence cannot settle the question; do not invent provider knowledge,
|
|
146
|
+
fetch other sources, widen the task, rewrite the visible request, or supply implementation advice.
|
|
147
|
+
You may correct false facts and add missing facts within an existing scope, but never silently drop unrelated
|
|
148
|
+
obligations. Do not place request IDs in public fact fields. ${CONTRACT_FACTS_ANALYST_INSTRUCTIONS}`;
|
|
149
|
+
const ANALYST_INSTRUCTIONS = `You are the repository-analysis role in a coding benchmark foundry.
|
|
150
|
+
Use only the supplied pre-change repository excerpts and mechanically established behavior evidence.
|
|
151
|
+
Identify the user-observable behavior, integration boundaries, preservation constraints, and ambiguity risks.
|
|
152
|
+
When requestedDimension is supplied, identify how the authentic seed exercises that area or explain why it does
|
|
153
|
+
not fit. Do not invent a different task merely to match the requested dimension. Preserve every critical seed behavior.
|
|
154
|
+
Select at most eight relevantPaths from the supplied contextPathInventory. Select unchanged public surfaces,
|
|
155
|
+
protocols, manifests, or bound tests when they are necessary to understand cross-file integration.
|
|
156
|
+
Do not write the task, tests, reference solution, or implementation advice.
|
|
157
|
+
Do not treat the historical patch as normative. Return only the requested structured object.`;
|
|
158
|
+
const SPECIFICATION_INSTRUCTIONS = `You are the specification-writer role in a coding benchmark foundry.
|
|
159
|
+
Write a realistic issue-style request for a coding agent working in the supplied pre-change checkout.
|
|
160
|
+
State user-observable behavior and necessary preservation constraints, but do not mention hidden tests,
|
|
161
|
+
the reference patch, post-change code, mutations, graders, or exact implementation steps.
|
|
162
|
+
The task must allow multiple behaviorally correct implementations and explicitly cover every supplied critical
|
|
163
|
+
seed behavior, with faithful paraphrases allowed. When requestedDimension is supplied, assess that area through
|
|
164
|
+
the authentic seed change without inventing unrelated requirements. Return only the requested structured object.`;
|
|
165
|
+
const criticInstructions = (perspective) => `You are an independent ${perspective} critic in a coding benchmark foundry.
|
|
166
|
+
Judge whether a capable coding agent can solve the visible task from the pre-change repository context
|
|
167
|
+
without seeing hidden tests or the historical patch. Look for unavailable context, multiple legitimate
|
|
168
|
+
interpretations, hidden-answer leakage, unrealistic phrasing, and unsupported assumptions.
|
|
169
|
+
Return exactly one criticalBehaviorCoverage record for every supplied critical targetBehavior id. Mark a behavior
|
|
170
|
+
covered only when the visible request states its complete requirement; semantic paraphrases are allowed. An omitted
|
|
171
|
+
or uncertain critical requirement is a blocker and requires verdict insufficient, even if the rest of the task is clear.
|
|
172
|
+
When requestedDimension is supplied, return dimensionFit for that exact request with concrete pre-change evidencePaths.
|
|
173
|
+
The task must actually assess that area through the seed change, not merely mention it. Mismatch or uncertainty is
|
|
174
|
+
a blocker and requires verdict insufficient. Do not force a seed to fit an unrelated dimension.
|
|
175
|
+
Do not repair or rewrite the task. Return only the requested structured review.`;
|
|
176
|
+
const boundedExcerpt = (content, remainingBytes) => {
|
|
177
|
+
if (remainingBytes <= 0)
|
|
178
|
+
return "";
|
|
179
|
+
const bytes = Buffer.from(content);
|
|
180
|
+
if (bytes.byteLength <= remainingBytes)
|
|
181
|
+
return content;
|
|
182
|
+
return `${bytes.subarray(0, Math.max(0, remainingBytes - 32)).toString("utf8")}\n[truncated]`;
|
|
183
|
+
};
|
|
184
|
+
const evidencePaths = (seed) => [
|
|
185
|
+
...new Set(seed.capabilityEvidence
|
|
186
|
+
.map((evidence) => evidence.path)
|
|
187
|
+
.filter((path) => path !== undefined))
|
|
188
|
+
].slice(0, 8);
|
|
189
|
+
const pathWithinRoot = (path, root) => root === "." || path === root || path.startsWith(`${root}/`);
|
|
190
|
+
export const repositoryGenerationContextCandidatesV1 = (input) => {
|
|
191
|
+
const relationships = new Map();
|
|
192
|
+
const add = (path, relationship) => {
|
|
193
|
+
if (path === undefined || path.trim().length === 0)
|
|
194
|
+
return;
|
|
195
|
+
const current = relationships.get(path) ?? new Set();
|
|
196
|
+
current.add(relationship);
|
|
197
|
+
relationships.set(path, current);
|
|
198
|
+
};
|
|
199
|
+
const seedPaths = input.seed.capabilityEvidence
|
|
200
|
+
.map((evidence) => evidence.path)
|
|
201
|
+
.filter((path) => path !== undefined);
|
|
202
|
+
for (const path of seedPaths)
|
|
203
|
+
add(path, "seed-evidence");
|
|
204
|
+
const episode = input.map.historyEpisodes.find((candidate) => "changeEpisodeId" in input.seed.source && candidate.id === input.seed.source.changeEpisodeId);
|
|
205
|
+
for (const changed of episode?.changedPaths ?? []) {
|
|
206
|
+
add(changed.path, "historical-change");
|
|
207
|
+
add(changed.previousPath, "historical-previous-path");
|
|
208
|
+
}
|
|
209
|
+
const owningPackageIds = new Set(seedPaths.flatMap((path) => {
|
|
210
|
+
const matches = input.map.packages
|
|
211
|
+
.filter((entry) => pathWithinRoot(path, entry.path))
|
|
212
|
+
.sort((left, right) => right.path.length - left.path.length || left.path.localeCompare(right.path));
|
|
213
|
+
const deepest = matches[0]?.path.length;
|
|
214
|
+
return deepest === undefined
|
|
215
|
+
? []
|
|
216
|
+
: matches.filter((entry) => entry.path.length === deepest).map((entry) => entry.id);
|
|
217
|
+
}));
|
|
218
|
+
const owningPackages = input.map.packages.filter((entry) => owningPackageIds.has(entry.id));
|
|
219
|
+
for (const owner of owningPackages) {
|
|
220
|
+
add(owner.manifestPath, "owning-package-manifest");
|
|
221
|
+
}
|
|
222
|
+
for (const surface of input.map.publicSurfaces) {
|
|
223
|
+
if ((surface.packageId !== undefined && owningPackageIds.has(surface.packageId)) ||
|
|
224
|
+
owningPackages.some((owner) => pathWithinRoot(surface.path, owner.path))) {
|
|
225
|
+
add(surface.path, "owning-public-surface");
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
for (const protocol of input.map.protocols) {
|
|
229
|
+
if (owningPackages.some((owner) => pathWithinRoot(protocol.path, owner.path))) {
|
|
230
|
+
add(protocol.path, "owning-protocol");
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
const relatedTargetIds = new Set([
|
|
234
|
+
...owningPackageIds,
|
|
235
|
+
...input.map.publicSurfaces
|
|
236
|
+
.filter((surface) => surface.packageId !== undefined && owningPackageIds.has(surface.packageId))
|
|
237
|
+
.map((surface) => surface.id),
|
|
238
|
+
...input.map.protocols
|
|
239
|
+
.filter((protocol) => owningPackages.some((owner) => pathWithinRoot(protocol.path, owner.path)))
|
|
240
|
+
.map((protocol) => protocol.id)
|
|
241
|
+
]);
|
|
242
|
+
const boundTestIds = new Set(input.map.testBindings
|
|
243
|
+
.filter((binding) => binding.targetIds.some((targetId) => relatedTargetIds.has(targetId)))
|
|
244
|
+
.map((binding) => binding.testId));
|
|
245
|
+
for (const test of input.map.tests) {
|
|
246
|
+
if (boundTestIds.has(test.id) || seedPaths.includes(test.path)) {
|
|
247
|
+
add(test.path, "behavior-bound-test");
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return [...relationships.entries()]
|
|
251
|
+
.map(([path, values]) => ({
|
|
252
|
+
path,
|
|
253
|
+
relationships: [...values].sort()
|
|
254
|
+
}))
|
|
255
|
+
.sort((left, right) => {
|
|
256
|
+
const leftSeed = left.relationships.includes("seed-evidence") ? 0 : 1;
|
|
257
|
+
const rightSeed = right.relationships.includes("seed-evidence") ? 0 : 1;
|
|
258
|
+
return leftSeed - rightSeed || left.path.localeCompare(right.path);
|
|
259
|
+
})
|
|
260
|
+
.slice(0, 64);
|
|
261
|
+
};
|
|
262
|
+
const readContextSources = Effect.fn("CaseAuthoring.readContextSources")(function* (input) {
|
|
263
|
+
const sources = [];
|
|
264
|
+
let remainingBytes = input.maximumBytes;
|
|
265
|
+
for (const path of input.paths.slice(0, input.maximumFiles)) {
|
|
266
|
+
if (!input.snapshot.files.includes(path) || remainingBytes <= 0)
|
|
267
|
+
continue;
|
|
268
|
+
const content = yield* readGitTreeFileV1({
|
|
269
|
+
snapshot: input.snapshot,
|
|
270
|
+
path
|
|
271
|
+
});
|
|
272
|
+
const bounded = boundedExcerpt(content, Math.min(remainingBytes, input.perFileBytes));
|
|
273
|
+
if (bounded.length === 0)
|
|
274
|
+
continue;
|
|
275
|
+
sources.push({ path, content: bounded });
|
|
276
|
+
remainingBytes -= Buffer.byteLength(bounded);
|
|
277
|
+
}
|
|
278
|
+
return sources;
|
|
279
|
+
});
|
|
280
|
+
const contextFailure = (detail) => new RepositoryFoundryError({
|
|
281
|
+
operation: "select-generation-context",
|
|
282
|
+
detail
|
|
283
|
+
});
|
|
284
|
+
export class CaseAuthoring extends Context.Service()("@velum-labs/routekit-eval-setup/CaseAuthoring") {
|
|
285
|
+
}
|
|
286
|
+
export const authorRepositoryCaseSpecificationV1 = Effect.fn("CaseAuthoring.authorSpecification")(function* (input) {
|
|
287
|
+
if (input.specificationContractFactsVersion !== undefined &&
|
|
288
|
+
(input.specificationContractFactsVersion !== 1 ||
|
|
289
|
+
input.maximumSpecificationRevisions === undefined)) {
|
|
290
|
+
return yield* contextFailure("contract facts require version 1 and an explicit specification revision allowance");
|
|
291
|
+
}
|
|
292
|
+
if (input.maximumSpecificationRevisions !== undefined) {
|
|
293
|
+
const grounded = yield* authorReferenceGroundedSpecification({
|
|
294
|
+
...input,
|
|
295
|
+
maximumSpecificationRevisions: input.maximumSpecificationRevisions
|
|
296
|
+
});
|
|
297
|
+
return grounded;
|
|
298
|
+
}
|
|
299
|
+
const languageModel = yield* RepositoryFoundryLanguageModel;
|
|
300
|
+
const dimensionContext = input.requestedDimension === undefined
|
|
301
|
+
? {}
|
|
302
|
+
: { requestedDimension: input.requestedDimension };
|
|
303
|
+
if (input.requestedDimension !== undefined &&
|
|
304
|
+
(input.requestedDimension.trim().length === 0 || input.requestedDimension.length > 2000)) {
|
|
305
|
+
return yield* contextFailure("requested dimension must contain between one and 2000 characters");
|
|
306
|
+
}
|
|
307
|
+
const snapshot = yield* captureGitTreeSnapshotV1({
|
|
308
|
+
repositoryRoot: input.repositoryRoot,
|
|
309
|
+
requestedRef: input.seed.initialState.commit
|
|
310
|
+
});
|
|
311
|
+
const seedEvidencePaths = evidencePaths(input.seed);
|
|
312
|
+
const excerpts = yield* readContextSources({
|
|
313
|
+
snapshot,
|
|
314
|
+
paths: seedEvidencePaths,
|
|
315
|
+
maximumFiles: 8,
|
|
316
|
+
maximumBytes: 60_000,
|
|
317
|
+
perFileBytes: 16_000
|
|
318
|
+
});
|
|
319
|
+
const contextPathInventory = repositoryGenerationContextCandidatesV1({
|
|
320
|
+
map: input.map,
|
|
321
|
+
seed: input.seed
|
|
322
|
+
}).filter((candidate) => snapshot.files.includes(candidate.path));
|
|
323
|
+
const publicEvidence = {
|
|
324
|
+
...dimensionContext,
|
|
325
|
+
seed: {
|
|
326
|
+
id: input.seed.id,
|
|
327
|
+
summary: input.seed.summary,
|
|
328
|
+
source: input.seed.source,
|
|
329
|
+
targetBehavior: input.seed.targetBehavior,
|
|
330
|
+
initialCommit: input.seed.initialState.commit
|
|
331
|
+
},
|
|
332
|
+
family: {
|
|
333
|
+
id: input.family.id,
|
|
334
|
+
capabilityId: input.family.capabilityId,
|
|
335
|
+
jobStatement: input.family.jobStatement,
|
|
336
|
+
inputStateFacets: input.family.inputStateFacets,
|
|
337
|
+
requestedChangeFacets: input.family.requestedChangeFacets,
|
|
338
|
+
observableFacets: input.family.observableFacets,
|
|
339
|
+
excludedNearMisses: input.family.excludedNearMisses
|
|
340
|
+
},
|
|
341
|
+
excerpts,
|
|
342
|
+
contextPathInventory
|
|
343
|
+
};
|
|
344
|
+
const analysis = yield* languageModel.generateStructured({
|
|
345
|
+
plan: input.modelPlan,
|
|
346
|
+
role: "repository-analyst",
|
|
347
|
+
operationId: `${input.operationId}:repository-analyst`,
|
|
348
|
+
instructions: ANALYST_INSTRUCTIONS,
|
|
349
|
+
input: publicEvidence,
|
|
350
|
+
schemaName: "routekit_repository_analysis_v1",
|
|
351
|
+
outputSchema: RepositoryAnalysisOutput,
|
|
352
|
+
maximumOutputTokens: repositoryFoundryRoleOutputCeilingV1("repository-analyst")
|
|
353
|
+
});
|
|
354
|
+
const selectedPaths = analysis.value.relevantPaths;
|
|
355
|
+
const availablePaths = new Set(contextPathInventory.map((candidate) => candidate.path));
|
|
356
|
+
if (selectedPaths.length === 0 ||
|
|
357
|
+
selectedPaths.length > 8 ||
|
|
358
|
+
new Set(selectedPaths).size !== selectedPaths.length ||
|
|
359
|
+
selectedPaths.some((path) => !availablePaths.has(path))) {
|
|
360
|
+
return yield* contextFailure("repository analyst must select between one and eight unique paths from the bounded context inventory");
|
|
361
|
+
}
|
|
362
|
+
const contextPaths = [...new Set([...seedEvidencePaths, ...selectedPaths])];
|
|
363
|
+
if (contextPaths.length > 12) {
|
|
364
|
+
return yield* contextFailure("repository analyst selection exceeds the twelve-file generation context bound");
|
|
365
|
+
}
|
|
366
|
+
const contextSources = yield* readContextSources({
|
|
367
|
+
snapshot,
|
|
368
|
+
paths: contextPaths,
|
|
369
|
+
maximumFiles: 12,
|
|
370
|
+
maximumBytes: 80_000,
|
|
371
|
+
perFileBytes: 20_000
|
|
372
|
+
});
|
|
373
|
+
if (contextSources.length !== contextPaths.length ||
|
|
374
|
+
seedEvidencePaths.some((path) => !contextSources.some((source) => source.path === path))) {
|
|
375
|
+
return yield* contextFailure("selected generation context is unavailable in the immutable pre-change snapshot");
|
|
376
|
+
}
|
|
377
|
+
const authored = yield* languageModel.generateStructured({
|
|
378
|
+
plan: input.modelPlan,
|
|
379
|
+
role: "specification-writer",
|
|
380
|
+
operationId: `${input.operationId}:specification-writer`,
|
|
381
|
+
instructions: SPECIFICATION_INSTRUCTIONS,
|
|
382
|
+
input: {
|
|
383
|
+
...dimensionContext,
|
|
384
|
+
targetBehavior: input.seed.targetBehavior,
|
|
385
|
+
analysis: analysis.value,
|
|
386
|
+
family: publicEvidence.family,
|
|
387
|
+
initialCommit: input.seed.initialState.commit,
|
|
388
|
+
selectedRepositoryContext: contextSources
|
|
389
|
+
},
|
|
390
|
+
schemaName: "routekit_repository_specification_v1",
|
|
391
|
+
outputSchema: RepositorySpecificationOutput,
|
|
392
|
+
maximumOutputTokens: repositoryFoundryRoleOutputCeilingV1("specification-writer")
|
|
393
|
+
});
|
|
394
|
+
const visible = {
|
|
395
|
+
lane: "repository-agent",
|
|
396
|
+
id: input.caseId,
|
|
397
|
+
requestText: authored.value.requestText,
|
|
398
|
+
checkoutCommit: input.seed.initialState.commit,
|
|
399
|
+
allowedTools: ["read", "search", "edit", "shell", "test"],
|
|
400
|
+
constraints: [
|
|
401
|
+
...new Set([
|
|
402
|
+
...authored.value.constraints,
|
|
403
|
+
"Do not weaken or delete tests to make the task pass.",
|
|
404
|
+
"Preserve unrelated public behavior."
|
|
405
|
+
])
|
|
406
|
+
]
|
|
407
|
+
};
|
|
408
|
+
const reviewInput = {
|
|
409
|
+
...dimensionContext,
|
|
410
|
+
targetBehavior: input.seed.targetBehavior,
|
|
411
|
+
visible,
|
|
412
|
+
analysis: analysis.value,
|
|
413
|
+
family: publicEvidence.family,
|
|
414
|
+
initialRepositoryExcerpts: contextSources
|
|
415
|
+
};
|
|
416
|
+
const [criticA, criticB] = yield* Effect.all([
|
|
417
|
+
languageModel.generateStructured({
|
|
418
|
+
plan: input.modelPlan,
|
|
419
|
+
role: "specification-critic-a",
|
|
420
|
+
operationId: `${input.operationId}:specification-critic-a`,
|
|
421
|
+
instructions: criticInstructions("solver"),
|
|
422
|
+
input: reviewInput,
|
|
423
|
+
schemaName: "routekit_repository_specification_review_v1",
|
|
424
|
+
outputSchema: RepositorySpecificationReviewOutput,
|
|
425
|
+
maximumOutputTokens: repositoryFoundryRoleOutputCeilingV1("specification-critic-a")
|
|
426
|
+
}),
|
|
427
|
+
languageModel.generateStructured({
|
|
428
|
+
plan: input.modelPlan,
|
|
429
|
+
role: "specification-critic-b",
|
|
430
|
+
operationId: `${input.operationId}:specification-critic-b`,
|
|
431
|
+
instructions: criticInstructions("ambiguity"),
|
|
432
|
+
input: reviewInput,
|
|
433
|
+
schemaName: "routekit_repository_specification_review_v1",
|
|
434
|
+
outputSchema: RepositorySpecificationReviewOutput,
|
|
435
|
+
maximumOutputTokens: repositoryFoundryRoleOutputCeilingV1("specification-critic-b")
|
|
436
|
+
})
|
|
437
|
+
], { concurrency: 2 });
|
|
438
|
+
const reviews = [
|
|
439
|
+
{
|
|
440
|
+
reviewerId: criticA.call.operationId,
|
|
441
|
+
reviewerKind: "independent-solver",
|
|
442
|
+
independentlyProduced: true,
|
|
443
|
+
...criticA.value
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
reviewerId: criticB.call.operationId,
|
|
447
|
+
reviewerKind: "model-critic",
|
|
448
|
+
independentlyProduced: true,
|
|
449
|
+
...criticB.value
|
|
450
|
+
}
|
|
451
|
+
];
|
|
452
|
+
const critique = yield* critiqueRepositoryTaskSpecificationV1({
|
|
453
|
+
repositoryRoot: input.repositoryRoot,
|
|
454
|
+
seed: input.seed,
|
|
455
|
+
family: input.family,
|
|
456
|
+
visible,
|
|
457
|
+
reviews,
|
|
458
|
+
...dimensionContext
|
|
459
|
+
});
|
|
460
|
+
if (critique.outcome !== "pass") {
|
|
461
|
+
return yield* contextFailure(`generated specification failed independent review: ${critique.rejectionReasons.join("; ")}`);
|
|
462
|
+
}
|
|
463
|
+
const result = {
|
|
464
|
+
version: 1,
|
|
465
|
+
caseId: input.caseId,
|
|
466
|
+
analysis: analysis.value,
|
|
467
|
+
contextSources,
|
|
468
|
+
visible,
|
|
469
|
+
reviews,
|
|
470
|
+
modelCalls: [analysis.call, authored.call, criticA.call, criticB.call]
|
|
471
|
+
};
|
|
472
|
+
return result;
|
|
473
|
+
});
|
|
474
|
+
// Absence is explicit for added/deleted files. Present files are never excerpted: an
|
|
475
|
+
// incomplete eligibility predicate is insufficient evidence for a historical task.
|
|
476
|
+
const readCompleteReferenceSources = Effect.fn("CaseAuthoring.readCompleteReferenceSources")(function* (input) {
|
|
477
|
+
const paths = [...new Set(input.paths)].sort();
|
|
478
|
+
if (paths.length === 0 || paths.length > 24) {
|
|
479
|
+
return yield* contextFailure("reference grounding requires between one and 24 complete source paths");
|
|
480
|
+
}
|
|
481
|
+
const sources = [];
|
|
482
|
+
let totalBytes = 0;
|
|
483
|
+
for (const [index, path] of paths.entries()) {
|
|
484
|
+
if (!input.before.files.includes(path) && !input.after.files.includes(path)) {
|
|
485
|
+
return yield* contextFailure("required reference-grounding source is unavailable in both pinned snapshots");
|
|
486
|
+
}
|
|
487
|
+
for (const phase of ["before", "after"]) {
|
|
488
|
+
const snapshot = input[phase];
|
|
489
|
+
const content = snapshot.files.includes(path)
|
|
490
|
+
? yield* readGitTreeFileV1({ snapshot, path })
|
|
491
|
+
: null;
|
|
492
|
+
const bytes = content === null ? 0 : Buffer.byteLength(content);
|
|
493
|
+
totalBytes += bytes;
|
|
494
|
+
if (bytes > 96_000 || totalBytes > 256_000) {
|
|
495
|
+
return yield* contextFailure("complete reference-grounding sources exceed the 96000-byte file or 256000-byte combined bound; no truncated evidence was submitted");
|
|
496
|
+
}
|
|
497
|
+
sources.push({
|
|
498
|
+
sourceId: `private-reference-${phase}-${String(index)}`,
|
|
499
|
+
phase,
|
|
500
|
+
path,
|
|
501
|
+
content
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return sources;
|
|
506
|
+
});
|
|
507
|
+
const referenceEvidenceValid = (evidence, sources, phase) => {
|
|
508
|
+
const source = sources.find((candidate) => candidate.sourceId === evidence.sourceId);
|
|
509
|
+
return (source !== undefined &&
|
|
510
|
+
source.content !== null &&
|
|
511
|
+
(phase === undefined || source.phase === phase) &&
|
|
512
|
+
Number.isSafeInteger(evidence.startLine) &&
|
|
513
|
+
Number.isSafeInteger(evidence.endLine) &&
|
|
514
|
+
evidence.startLine >= 1 &&
|
|
515
|
+
evidence.endLine >= evidence.startLine &&
|
|
516
|
+
evidence.endLine <= source.content.split("\n").length &&
|
|
517
|
+
source.content
|
|
518
|
+
.split("\n")
|
|
519
|
+
.slice(evidence.startLine - 1, evidence.endLine)
|
|
520
|
+
.join("\n")
|
|
521
|
+
.trim().length > 0);
|
|
522
|
+
};
|
|
523
|
+
const referenceScopeFailures = (scope, sources, seed) => {
|
|
524
|
+
if (scope === undefined)
|
|
525
|
+
return ["private analyst did not return evidence-grounded behavioral scope"];
|
|
526
|
+
const knownBehaviorIds = new Set(seed.targetBehavior.map((behavior) => behavior.id));
|
|
527
|
+
if (scope.clauses.length === 0 ||
|
|
528
|
+
scope.clauses.length > 32 ||
|
|
529
|
+
new Set(scope.clauses.map((clause) => clause.id)).size !== scope.clauses.length ||
|
|
530
|
+
!scope.clauses.some((clause) => clause.kind === "changed") ||
|
|
531
|
+
scope.unresolvedQuestions.length > 16 ||
|
|
532
|
+
scope.unresolvedQuestions.some((question) => question.trim().length === 0 || question.length > 8000) ||
|
|
533
|
+
scope.clauses.some((clause) => clause.id.trim().length === 0 ||
|
|
534
|
+
clause.description.trim().length === 0 ||
|
|
535
|
+
clause.behaviorIds.length === 0 ||
|
|
536
|
+
new Set(clause.behaviorIds).size !== clause.behaviorIds.length ||
|
|
537
|
+
clause.behaviorIds.some((id) => !knownBehaviorIds.has(id)) ||
|
|
538
|
+
clause.evidence.length === 0 ||
|
|
539
|
+
clause.evidence.some((entry) => !referenceEvidenceValid(entry, sources)) ||
|
|
540
|
+
!clause.evidence.some((entry) => referenceEvidenceValid(entry, sources, "after")) ||
|
|
541
|
+
!clause.evidence.some((entry) => referenceEvidenceValid(entry, sources, "before"))) ||
|
|
542
|
+
seed.targetBehavior.some((behavior) => !scope.clauses.some((clause) => clause.behaviorIds.includes(behavior.id)))) {
|
|
543
|
+
return [
|
|
544
|
+
"private analyst scope is incomplete, malformed, or lacks valid pinned source line evidence for every critical behavior"
|
|
545
|
+
];
|
|
546
|
+
}
|
|
547
|
+
return [];
|
|
548
|
+
};
|
|
549
|
+
const referenceCompatibilityFailures = (review, scope, sources, pendingQuestions, visible) => {
|
|
550
|
+
const compatibility = review.referenceCompatibility;
|
|
551
|
+
if (compatibility === undefined)
|
|
552
|
+
return ["reference compatibility review is missing"];
|
|
553
|
+
const ids = compatibility.scopeCoverage.map((coverage) => coverage.scopeId);
|
|
554
|
+
if (compatibility.outcome !== "compatible" ||
|
|
555
|
+
compatibility.detail.trim().length === 0 ||
|
|
556
|
+
ids.length !== scope.clauses.length ||
|
|
557
|
+
new Set(ids).size !== ids.length ||
|
|
558
|
+
scope.clauses.some((clause) => !ids.includes(clause.id)) ||
|
|
559
|
+
compatibility.scopeCoverage.some((coverage) => coverage.outcome !== "supported" ||
|
|
560
|
+
coverage.detail.trim().length === 0 ||
|
|
561
|
+
coverage.evidence.length === 0 ||
|
|
562
|
+
coverage.evidence.some((entry) => !referenceEvidenceValid(entry, sources, "after")))) {
|
|
563
|
+
return [
|
|
564
|
+
"visible requirements are contradictory, uncertain, or lack complete pinned reference compatibility evidence"
|
|
565
|
+
];
|
|
566
|
+
}
|
|
567
|
+
const resolutions = compatibility.questionResolutions ?? [];
|
|
568
|
+
const questionIds = new Set(pendingQuestions.map((question) => question.id));
|
|
569
|
+
const resolutionIds = resolutions.map((resolution) => resolution.questionId);
|
|
570
|
+
const visibleFields = visible.lane === "repository-agent"
|
|
571
|
+
? [visible.requestText, ...visible.constraints]
|
|
572
|
+
: [visible.request.bodyJson];
|
|
573
|
+
if (resolutions.length !== questionIds.size ||
|
|
574
|
+
new Set(resolutionIds).size !== resolutionIds.length ||
|
|
575
|
+
resolutions.some((resolution) => !questionIds.has(resolution.questionId) ||
|
|
576
|
+
resolution.outcome === "unresolved" ||
|
|
577
|
+
resolution.detail.trim().length === 0 ||
|
|
578
|
+
new Set(resolution.affectedScopeIds).size !== resolution.affectedScopeIds.length ||
|
|
579
|
+
resolution.affectedScopeIds.some((id) => !scope.clauses.some((clause) => clause.id === id)) ||
|
|
580
|
+
resolution.evidence.some((entry) => !referenceEvidenceValid(entry, sources, "after")) ||
|
|
581
|
+
(resolution.outcome === "answered" && resolution.evidence.length === 0) ||
|
|
582
|
+
(resolution.outcome === "not-required" &&
|
|
583
|
+
(resolution.affectedScopeIds.length > 0 ||
|
|
584
|
+
resolution.visibleScopeExclusion === undefined ||
|
|
585
|
+
resolution.visibleScopeExclusion.quotation.trim().length === 0 ||
|
|
586
|
+
!visibleFields.some((field) => field.includes(resolution.visibleScopeExclusion.quotation)) ||
|
|
587
|
+
resolution.visibleScopeExclusion.rationale.trim().length === 0)))) {
|
|
588
|
+
return [
|
|
589
|
+
"private analyst questions require complete evidence-backed answers or justified visible-scope exclusions; unresolved or malformed resolutions block approval"
|
|
590
|
+
];
|
|
591
|
+
}
|
|
592
|
+
return [];
|
|
593
|
+
};
|
|
594
|
+
// This classifies an unsuitable target, never an admissible specification. Both
|
|
595
|
+
// independently requested critics must agree on the exact requested dimension
|
|
596
|
+
// after establishing all authentic critical behavior and grounded scope.
|
|
597
|
+
// Remaining reference uncertainty still blocks admission; it does not require
|
|
598
|
+
// more prose repair of a grounded, unanimous dimension mismatch. This rejection
|
|
599
|
+
// does not establish that every unanswered reference question is ancillary.
|
|
600
|
+
const hasIndependentGroundedDimensionMismatch = (input) => {
|
|
601
|
+
if (input.requestedDimension === undefined || input.reviews.length !== 2)
|
|
602
|
+
return false;
|
|
603
|
+
const criticalIds = new Set(input.targetBehavior.filter((behavior) => behavior.critical).map((behavior) => behavior.id));
|
|
604
|
+
if (criticalIds.size === 0)
|
|
605
|
+
return false;
|
|
606
|
+
const reviewerIds = [
|
|
607
|
+
`${input.operationPrefix}:specification-critic-a`,
|
|
608
|
+
`${input.operationPrefix}:specification-critic-b`
|
|
609
|
+
];
|
|
610
|
+
const reviewerKinds = ["independent-solver", "model-critic"];
|
|
611
|
+
if (new Set(input.reviews.map((review) => review.reviewerId)).size !== 2 ||
|
|
612
|
+
!input.reviews.every((review, index) => {
|
|
613
|
+
const fit = review.dimensionFit;
|
|
614
|
+
const coverage = review.criticalBehaviorCoverage;
|
|
615
|
+
if (!review.independentlyProduced ||
|
|
616
|
+
review.reviewerId !== reviewerIds[index] ||
|
|
617
|
+
review.reviewerKind !== reviewerKinds[index] ||
|
|
618
|
+
fit === undefined ||
|
|
619
|
+
fit.requestedDimension !== input.requestedDimension ||
|
|
620
|
+
fit.outcome !== "mismatch" ||
|
|
621
|
+
fit.detail.trim().length === 0 ||
|
|
622
|
+
fit.evidencePaths.length === 0 ||
|
|
623
|
+
fit.evidencePaths.some((path) => !input.before.files.includes(path)) ||
|
|
624
|
+
coverage === undefined)
|
|
625
|
+
return false;
|
|
626
|
+
const ids = coverage.map((entry) => entry.behaviorId);
|
|
627
|
+
return (ids.length === criticalIds.size &&
|
|
628
|
+
new Set(ids).size === ids.length &&
|
|
629
|
+
ids.every((id) => criticalIds.has(id)) &&
|
|
630
|
+
coverage.every((entry) => entry.outcome === "covered" && entry.detail.trim().length > 0));
|
|
631
|
+
}))
|
|
632
|
+
return false;
|
|
633
|
+
const compatibility = input.reviews[1].referenceCompatibility;
|
|
634
|
+
if (compatibility === undefined ||
|
|
635
|
+
compatibility.outcome === "contradictory" ||
|
|
636
|
+
compatibility.detail.trim().length === 0 ||
|
|
637
|
+
input.scope.clauses.length === 0)
|
|
638
|
+
return false;
|
|
639
|
+
const scopeIds = compatibility.scopeCoverage.map((coverage) => coverage.scopeId);
|
|
640
|
+
return (scopeIds.length === input.scope.clauses.length &&
|
|
641
|
+
new Set(scopeIds).size === scopeIds.length &&
|
|
642
|
+
input.scope.clauses.every((clause) => scopeIds.includes(clause.id)) &&
|
|
643
|
+
compatibility.scopeCoverage.every((coverage) => coverage.outcome === "supported" &&
|
|
644
|
+
coverage.detail.trim().length > 0 &&
|
|
645
|
+
coverage.evidence.length > 0 &&
|
|
646
|
+
coverage.evidence.every((entry) => referenceEvidenceValid(entry, input.sources, "after"))));
|
|
647
|
+
};
|
|
648
|
+
// The only reference-derived material allowed across the public author boundary is
|
|
649
|
+
// behavior prose. This catches verbatim private identifiers/code in that projection;
|
|
650
|
+
// structured provenance and complete after sources are never copied into it.
|
|
651
|
+
const containsPrivateReferenceMaterial = (value, sources, referenceCommit) => {
|
|
652
|
+
const text = JSON.stringify(value);
|
|
653
|
+
if (text.includes("private-reference-question-") ||
|
|
654
|
+
text.includes(referenceCommit) ||
|
|
655
|
+
text.includes(referenceCommit.slice(0, 12)) ||
|
|
656
|
+
sources.some((source) => text.includes(source.sourceId)))
|
|
657
|
+
return true;
|
|
658
|
+
const beforeLines = new Set(sources
|
|
659
|
+
.filter((source) => source.phase === "before")
|
|
660
|
+
.flatMap((source) => source.content?.split("\n").map((line) => line.trim()) ?? []));
|
|
661
|
+
return sources
|
|
662
|
+
.filter((source) => source.phase === "after")
|
|
663
|
+
.some((source) => source.content?.split("\n").some((line) => {
|
|
664
|
+
const normalized = line.trim();
|
|
665
|
+
return (normalized.length >= 32 &&
|
|
666
|
+
!beforeLines.has(normalized) &&
|
|
667
|
+
text.includes(JSON.stringify(normalized).slice(1, -1)));
|
|
668
|
+
}) === true);
|
|
669
|
+
};
|
|
670
|
+
const assertBoundedReferenceInput = (value) => Buffer.byteLength(JSON.stringify(value)) <= 512_000
|
|
671
|
+
? Effect.void
|
|
672
|
+
: Effect.fail(contextFailure("complete reference-grounded authoring input exceeds 512000 bytes; no evidence was truncated"));
|
|
673
|
+
const authorReferenceGroundedSpecification = Effect.fn("CaseAuthoring.authorReferenceGroundedSpecification")(function* (input) {
|
|
674
|
+
const maximumRevisions = input.maximumSpecificationRevisions;
|
|
675
|
+
if (!Number.isSafeInteger(maximumRevisions) || maximumRevisions < 0 || maximumRevisions > 2) {
|
|
676
|
+
return yield* contextFailure("maximum specification revisions must be an integer between zero and two");
|
|
677
|
+
}
|
|
678
|
+
if (input.seed.referenceCommit === undefined ||
|
|
679
|
+
!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/u.test(input.seed.referenceCommit)) {
|
|
680
|
+
return yield* contextFailure("reference-grounded authoring requires a pinned full reference commit");
|
|
681
|
+
}
|
|
682
|
+
if (input.requestedDimension !== undefined &&
|
|
683
|
+
(input.requestedDimension.trim().length === 0 || input.requestedDimension.length > 2000)) {
|
|
684
|
+
return yield* contextFailure("requested dimension must contain between one and 2000 characters");
|
|
685
|
+
}
|
|
686
|
+
const languageModel = yield* RepositoryFoundryLanguageModel;
|
|
687
|
+
const dimensionContext = input.requestedDimension === undefined ? {} : { requestedDimension: input.requestedDimension };
|
|
688
|
+
const before = yield* captureGitTreeSnapshotV1({
|
|
689
|
+
repositoryRoot: input.repositoryRoot,
|
|
690
|
+
requestedRef: input.seed.initialState.commit
|
|
691
|
+
});
|
|
692
|
+
const after = yield* captureGitTreeSnapshotV1({
|
|
693
|
+
repositoryRoot: input.repositoryRoot,
|
|
694
|
+
requestedRef: input.seed.referenceCommit
|
|
695
|
+
});
|
|
696
|
+
if (before.commit === after.commit) {
|
|
697
|
+
return yield* contextFailure("reference grounding requires distinct before and after commits");
|
|
698
|
+
}
|
|
699
|
+
const episode = input.map.historyEpisodes.find((candidate) => "changeEpisodeId" in input.seed.source && candidate.id === input.seed.source.changeEpisodeId);
|
|
700
|
+
const requiredPaths = [
|
|
701
|
+
...new Set([
|
|
702
|
+
...input.seed.capabilityEvidence.flatMap((evidence) => evidence.path === undefined ? [] : [evidence.path]),
|
|
703
|
+
...input.seed.targetBehavior.flatMap((behavior) => behavior.evidence.flatMap((evidence) => evidence.path === undefined ? [] : [evidence.path])),
|
|
704
|
+
...input.map.tests
|
|
705
|
+
.filter((entry) => input.seed.candidateTestIds.includes(entry.id))
|
|
706
|
+
.map((entry) => entry.path),
|
|
707
|
+
...(episode?.changedPaths.flatMap((entry) => entry.previousPath === undefined ? [entry.path] : [entry.previousPath, entry.path]) ?? [])
|
|
708
|
+
])
|
|
709
|
+
];
|
|
710
|
+
let privateSources = yield* readCompleteReferenceSources({ before, after, paths: requiredPaths });
|
|
711
|
+
const contextPathInventory = repositoryGenerationContextCandidatesV1({
|
|
712
|
+
map: input.map,
|
|
713
|
+
seed: input.seed
|
|
714
|
+
}).filter((candidate) => before.files.includes(candidate.path));
|
|
715
|
+
const familyContext = {
|
|
716
|
+
id: input.family.id,
|
|
717
|
+
capabilityId: input.family.capabilityId,
|
|
718
|
+
jobStatement: input.family.jobStatement,
|
|
719
|
+
inputStateFacets: input.family.inputStateFacets,
|
|
720
|
+
requestedChangeFacets: input.family.requestedChangeFacets,
|
|
721
|
+
observableFacets: input.family.observableFacets,
|
|
722
|
+
excludedNearMisses: input.family.excludedNearMisses
|
|
723
|
+
};
|
|
724
|
+
const analystInput = {
|
|
725
|
+
...dimensionContext,
|
|
726
|
+
targetBehavior: input.seed.targetBehavior,
|
|
727
|
+
family: familyContext,
|
|
728
|
+
contextPathInventory,
|
|
729
|
+
privateReferenceEvidence: {
|
|
730
|
+
beforeCommit: before.commit,
|
|
731
|
+
referenceCommit: after.commit,
|
|
732
|
+
sources: privateSources
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
yield* assertBoundedReferenceInput(analystInput);
|
|
736
|
+
const analysisRequest = {
|
|
737
|
+
plan: input.modelPlan,
|
|
738
|
+
role: "repository-analyst",
|
|
739
|
+
operationId: `${input.operationId}:repository-analyst`,
|
|
740
|
+
instructions: `${REFERENCE_ANALYST_INSTRUCTIONS}\nSelect at most eight relevantPaths from contextPathInventory. Preserve authentic requestedDimension fit without inventing a different task. Each scope clause must name its related target behaviorIds; preserve the IDs while grounding the actual observable requirement.`,
|
|
741
|
+
input: analystInput,
|
|
742
|
+
schemaName: "routekit_repository_analysis_v1",
|
|
743
|
+
outputSchema: RepositoryAnalysisOutput,
|
|
744
|
+
maximumOutputTokens: repositoryFoundryRoleOutputCeilingV1("repository-analyst")
|
|
745
|
+
};
|
|
746
|
+
const analysis = yield* (input.specificationContractFactsVersion === 1
|
|
747
|
+
? languageModel.generateStructured({
|
|
748
|
+
...analysisRequest,
|
|
749
|
+
instructions: `${analysisRequest.instructions}\n\n${CONTRACT_FACTS_ANALYST_INSTRUCTIONS}`,
|
|
750
|
+
schemaName: "routekit_repository_analysis_contract_facts_v1",
|
|
751
|
+
outputSchema: RepositoryContractFactsAnalysisOutput
|
|
752
|
+
})
|
|
753
|
+
: languageModel.generateStructured(analysisRequest));
|
|
754
|
+
const scopeErrors = referenceScopeFailures(analysis.value.referenceScope, privateSources, input.seed);
|
|
755
|
+
if (scopeErrors.length > 0 || analysis.value.referenceScope === undefined) {
|
|
756
|
+
return yield* contextFailure(scopeErrors.join("; "));
|
|
757
|
+
}
|
|
758
|
+
const scope = analysis.value.referenceScope;
|
|
759
|
+
const pendingQuestions = scope.unresolvedQuestions.map((question, index) => ({
|
|
760
|
+
id: `private-reference-question-${String(index + 1)}`,
|
|
761
|
+
question
|
|
762
|
+
}));
|
|
763
|
+
const availablePaths = new Set(contextPathInventory.map((candidate) => candidate.path));
|
|
764
|
+
const selectedPaths = analysis.value.relevantPaths;
|
|
765
|
+
if (selectedPaths.length === 0 ||
|
|
766
|
+
selectedPaths.length > 8 ||
|
|
767
|
+
new Set(selectedPaths).size !== selectedPaths.length ||
|
|
768
|
+
selectedPaths.some((path) => !availablePaths.has(path))) {
|
|
769
|
+
return yield* contextFailure("repository analyst must select between one and eight unique paths from the bounded context inventory");
|
|
770
|
+
}
|
|
771
|
+
const contextPaths = [
|
|
772
|
+
...new Set([...requiredPaths.filter((path) => before.files.includes(path)), ...selectedPaths])
|
|
773
|
+
];
|
|
774
|
+
if (contextPaths.length > 12) {
|
|
775
|
+
return yield* contextFailure("complete pre-change generation context exceeds twelve files");
|
|
776
|
+
}
|
|
777
|
+
privateSources = yield* readCompleteReferenceSources({
|
|
778
|
+
before,
|
|
779
|
+
after,
|
|
780
|
+
paths: [...requiredPaths, ...selectedPaths]
|
|
781
|
+
});
|
|
782
|
+
// IDs derive from sorted path ordinals. Reloading with selected paths must not
|
|
783
|
+
// rebind the analyst's evidence to another file.
|
|
784
|
+
const analystSources = analystInput.privateReferenceEvidence.sources;
|
|
785
|
+
privateSources = privateSources.map((source) => ({
|
|
786
|
+
...source,
|
|
787
|
+
sourceId: analystSources.find((entry) => entry.phase === source.phase && entry.path === source.path)
|
|
788
|
+
?.sourceId ??
|
|
789
|
+
`private-reference-selected-${source.phase}-${String(contextPaths.indexOf(source.path))}`
|
|
790
|
+
}));
|
|
791
|
+
const contextSources = privateSources
|
|
792
|
+
.filter((source) => source.phase === "before" && source.content !== null && contextPaths.includes(source.path))
|
|
793
|
+
.map((source) => ({ path: source.path, content: source.content }));
|
|
794
|
+
const publicAnalysis = {
|
|
795
|
+
summary: analysis.value.summary,
|
|
796
|
+
userObservableBehaviors: analysis.value.userObservableBehaviors,
|
|
797
|
+
constraints: analysis.value.constraints,
|
|
798
|
+
risks: analysis.value.risks,
|
|
799
|
+
relevantPaths: analysis.value.relevantPaths
|
|
800
|
+
};
|
|
801
|
+
const behavioralScope = scope.clauses.map((clause) => ({
|
|
802
|
+
id: clause.id,
|
|
803
|
+
kind: clause.kind,
|
|
804
|
+
behaviorIds: clause.behaviorIds,
|
|
805
|
+
description: clause.description
|
|
806
|
+
}));
|
|
807
|
+
if (containsPrivateReferenceMaterial({ publicAnalysis, behavioralScope }, privateSources, after.commit)) {
|
|
808
|
+
return yield* contextFailure("private reference material leaked into the analyst's public behavioral projection");
|
|
809
|
+
}
|
|
810
|
+
if (input.specificationContractFactsVersion === 1) {
|
|
811
|
+
const markedAnalysis = yield* Effect.try({
|
|
812
|
+
try: () => Schema.decodeUnknownSync(RepositoryContractFactsAnalysisOutput, {
|
|
813
|
+
onExcessProperty: "error"
|
|
814
|
+
})(analysis.value),
|
|
815
|
+
catch: () => contextFailure("marked analyst did not return strict contract facts")
|
|
816
|
+
});
|
|
817
|
+
return yield* authorContractFactsSpecification({
|
|
818
|
+
request: input,
|
|
819
|
+
analysis: markedAnalysis,
|
|
820
|
+
analystCall: analysis.call,
|
|
821
|
+
before,
|
|
822
|
+
after,
|
|
823
|
+
privateSources,
|
|
824
|
+
contextSources,
|
|
825
|
+
publicAnalysis,
|
|
826
|
+
familyContext
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
const groundedTargetBehavior = input.seed.targetBehavior.map((behavior) => ({
|
|
830
|
+
...behavior,
|
|
831
|
+
description: scope.clauses
|
|
832
|
+
.filter((clause) => clause.behaviorIds.includes(behavior.id))
|
|
833
|
+
.map((clause) => clause.description)
|
|
834
|
+
.join(" ")
|
|
835
|
+
}));
|
|
836
|
+
const publicContext = {
|
|
837
|
+
...dimensionContext,
|
|
838
|
+
targetBehavior: groundedTargetBehavior,
|
|
839
|
+
analysis: publicAnalysis,
|
|
840
|
+
behavioralScope,
|
|
841
|
+
family: familyContext
|
|
842
|
+
};
|
|
843
|
+
const history = [];
|
|
844
|
+
const modelCalls = [analysis.call];
|
|
845
|
+
let revisionFeedback = [];
|
|
846
|
+
let previousVisible;
|
|
847
|
+
for (let sequence = 0; sequence <= maximumRevisions; sequence += 1) {
|
|
848
|
+
const operationPrefix = sequence === 0
|
|
849
|
+
? input.operationId
|
|
850
|
+
: `${input.operationId}:specification-revision:${String(sequence)}`;
|
|
851
|
+
const writerInput = {
|
|
852
|
+
...publicContext,
|
|
853
|
+
initialCommit: before.commit,
|
|
854
|
+
selectedRepositoryContext: contextSources,
|
|
855
|
+
...(sequence === 0 ? {} : { previousVisible, behavioralReviewFeedback: revisionFeedback })
|
|
856
|
+
};
|
|
857
|
+
yield* assertBoundedReferenceInput(writerInput);
|
|
858
|
+
const authored = yield* languageModel.generateStructured({
|
|
859
|
+
plan: input.modelPlan,
|
|
860
|
+
role: "specification-writer",
|
|
861
|
+
operationId: `${operationPrefix}:specification-writer`,
|
|
862
|
+
instructions: `${SPECIFICATION_INSTRUCTIONS}\nThe supplied behavioralScope is grounded in the repository's observable behavior. State its eligibility and preservation boundaries explicitly. Mechanically inferred targetBehavior descriptions are hypotheses; preserve their authentic requirements without broadening the grounded scope.${sequence === 0 ? "" : `\n${SPECIFICATION_REVISION_INSTRUCTIONS}`}`,
|
|
863
|
+
input: writerInput,
|
|
864
|
+
schemaName: "routekit_repository_specification_v1",
|
|
865
|
+
outputSchema: RepositorySpecificationOutput,
|
|
866
|
+
maximumOutputTokens: repositoryFoundryRoleOutputCeilingV1("specification-writer")
|
|
867
|
+
});
|
|
868
|
+
modelCalls.push(authored.call);
|
|
869
|
+
const visible = {
|
|
870
|
+
lane: "repository-agent",
|
|
871
|
+
id: input.caseId,
|
|
872
|
+
requestText: authored.value.requestText,
|
|
873
|
+
checkoutCommit: before.commit,
|
|
874
|
+
allowedTools: ["read", "search", "edit", "shell", "test"],
|
|
875
|
+
constraints: [
|
|
876
|
+
...new Set([
|
|
877
|
+
...authored.value.constraints,
|
|
878
|
+
"Do not weaken or delete tests to make the task pass.",
|
|
879
|
+
"Preserve unrelated public behavior."
|
|
880
|
+
])
|
|
881
|
+
]
|
|
882
|
+
};
|
|
883
|
+
if (containsPrivateReferenceMaterial(visible, privateSources, after.commit)) {
|
|
884
|
+
return yield* contextFailure("private reference material leaked into the visible specification");
|
|
885
|
+
}
|
|
886
|
+
const reviewInput = { ...publicContext, visible, initialRepositoryExcerpts: contextSources };
|
|
887
|
+
const privateReviewInput = {
|
|
888
|
+
...reviewInput,
|
|
889
|
+
privateReferenceEvidence: {
|
|
890
|
+
beforeCommit: before.commit,
|
|
891
|
+
referenceCommit: after.commit,
|
|
892
|
+
sources: privateSources,
|
|
893
|
+
pendingQuestions
|
|
894
|
+
}
|
|
895
|
+
};
|
|
896
|
+
yield* assertBoundedReferenceInput(privateReviewInput);
|
|
897
|
+
const [criticA, criticB] = yield* Effect.all([
|
|
898
|
+
languageModel.generateStructured({
|
|
899
|
+
plan: input.modelPlan,
|
|
900
|
+
role: "specification-critic-a",
|
|
901
|
+
operationId: `${operationPrefix}:specification-critic-a`,
|
|
902
|
+
instructions: `${criticInstructions("solver")}\nThe supplied behavioralScope defines authentic eligibility and preservation boundaries. Check the visible task covers every grounded clause, retaining critical behavior IDs without expanding scope from a mechanically inferred summary. You remain blind to the reference implementation.`,
|
|
903
|
+
input: reviewInput,
|
|
904
|
+
schemaName: "routekit_repository_specification_review_v1",
|
|
905
|
+
outputSchema: RepositorySpecificationReviewOutput,
|
|
906
|
+
maximumOutputTokens: repositoryFoundryRoleOutputCeilingV1("specification-critic-a")
|
|
907
|
+
}),
|
|
908
|
+
languageModel.generateStructured({
|
|
909
|
+
plan: input.modelPlan,
|
|
910
|
+
role: "specification-critic-b",
|
|
911
|
+
operationId: `${operationPrefix}:specification-critic-b`,
|
|
912
|
+
instructions: `${criticInstructions("ambiguity")}\n\n${REFERENCE_CRITIC_INSTRUCTIONS}`,
|
|
913
|
+
input: privateReviewInput,
|
|
914
|
+
schemaName: "routekit_repository_specification_review_v1",
|
|
915
|
+
outputSchema: RepositorySpecificationReviewOutput,
|
|
916
|
+
maximumOutputTokens: repositoryFoundryRoleOutputCeilingV1("specification-critic-b")
|
|
917
|
+
})
|
|
918
|
+
], { concurrency: 2 });
|
|
919
|
+
modelCalls.push(criticA.call, criticB.call);
|
|
920
|
+
const compatibilityFailures = referenceCompatibilityFailures(criticB.value, scope, privateSources, pendingQuestions, visible);
|
|
921
|
+
const reviews = [
|
|
922
|
+
{
|
|
923
|
+
reviewerId: criticA.call.operationId,
|
|
924
|
+
reviewerKind: "independent-solver",
|
|
925
|
+
independentlyProduced: true,
|
|
926
|
+
...criticA.value
|
|
927
|
+
},
|
|
928
|
+
{
|
|
929
|
+
reviewerId: criticB.call.operationId,
|
|
930
|
+
reviewerKind: "model-critic",
|
|
931
|
+
independentlyProduced: true,
|
|
932
|
+
...criticB.value,
|
|
933
|
+
...(compatibilityFailures.length === 0
|
|
934
|
+
? {}
|
|
935
|
+
: {
|
|
936
|
+
verdict: "insufficient",
|
|
937
|
+
detail: [criticB.value.detail, ...compatibilityFailures].join(" "),
|
|
938
|
+
findings: [
|
|
939
|
+
...criticB.value.findings,
|
|
940
|
+
...compatibilityFailures.map((detail) => ({
|
|
941
|
+
axis: "unsupported-assumption",
|
|
942
|
+
severity: "blocker",
|
|
943
|
+
detail
|
|
944
|
+
}))
|
|
945
|
+
]
|
|
946
|
+
})
|
|
947
|
+
}
|
|
948
|
+
];
|
|
949
|
+
const critique = yield* critiqueRepositoryTaskSpecificationV1({
|
|
950
|
+
repositoryRoot: input.repositoryRoot,
|
|
951
|
+
seed: { ...input.seed, targetBehavior: groundedTargetBehavior },
|
|
952
|
+
family: input.family,
|
|
953
|
+
visible,
|
|
954
|
+
reviews,
|
|
955
|
+
...dimensionContext
|
|
956
|
+
});
|
|
957
|
+
history.push({ sequence, visible, reviews, rejectionReasons: critique.rejectionReasons });
|
|
958
|
+
if (critique.outcome === "pass") {
|
|
959
|
+
return {
|
|
960
|
+
version: 1,
|
|
961
|
+
caseId: input.caseId,
|
|
962
|
+
analysis: analysis.value,
|
|
963
|
+
contextSources,
|
|
964
|
+
visible,
|
|
965
|
+
reviews,
|
|
966
|
+
modelCalls,
|
|
967
|
+
groundedTargetBehavior,
|
|
968
|
+
referenceGrounding: {
|
|
969
|
+
beforeCommit: before.commit,
|
|
970
|
+
referenceCommit: after.commit,
|
|
971
|
+
sources: privateSources,
|
|
972
|
+
scope
|
|
973
|
+
},
|
|
974
|
+
specificationRevisions: history
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
if (hasIndependentGroundedDimensionMismatch({
|
|
978
|
+
...dimensionContext,
|
|
979
|
+
operationPrefix,
|
|
980
|
+
before,
|
|
981
|
+
targetBehavior: groundedTargetBehavior,
|
|
982
|
+
reviews,
|
|
983
|
+
scope,
|
|
984
|
+
sources: privateSources
|
|
985
|
+
})) {
|
|
986
|
+
return yield* new RepositoryFoundryError({
|
|
987
|
+
operation: "select-generation-context",
|
|
988
|
+
detail: "generated specification cannot assess the pinned requested dimension: two independent critics established a definite mismatch with complete grounded scope and critical behavior evidence",
|
|
989
|
+
generationRejection: {
|
|
990
|
+
code: "specification-dimension-mismatch",
|
|
991
|
+
completedRevisions: sequence
|
|
992
|
+
}
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
if (sequence === maximumRevisions) {
|
|
996
|
+
const publicReasons = critique.rejectionReasons.map((detail) => containsPrivateReferenceMaterial(detail, privateSources, after.commit)
|
|
997
|
+
? "A private reference compatibility finding blocks this specification."
|
|
998
|
+
: detail);
|
|
999
|
+
return yield* new RepositoryFoundryError({
|
|
1000
|
+
operation: "select-generation-context",
|
|
1001
|
+
detail: `generated specification failed independent review after ${String(sequence)} bounded revisions: ${publicReasons.join("; ")}`,
|
|
1002
|
+
generationRejection: {
|
|
1003
|
+
code: "specification-review-exhausted",
|
|
1004
|
+
completedRevisions: sequence
|
|
1005
|
+
}
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
// The writer receives prose findings only, never source refs, full private
|
|
1009
|
+
// review objects, or raw repository snippets from the compatibility critic.
|
|
1010
|
+
revisionFeedback = reviews
|
|
1011
|
+
.flatMap((review) => [
|
|
1012
|
+
review.detail,
|
|
1013
|
+
...(review.dimensionFit === undefined ? [] : [review.dimensionFit.detail]),
|
|
1014
|
+
...review.findings.map((finding) => finding.detail),
|
|
1015
|
+
...(review.criticalBehaviorCoverage
|
|
1016
|
+
?.filter((entry) => entry.outcome !== "covered")
|
|
1017
|
+
.map((entry) => entry.detail) ?? []),
|
|
1018
|
+
...(review.referenceCompatibility?.scopeCoverage
|
|
1019
|
+
.filter((entry) => entry.outcome !== "supported")
|
|
1020
|
+
.map((entry) => entry.detail) ?? []),
|
|
1021
|
+
...(review.referenceCompatibility?.questionResolutions
|
|
1022
|
+
?.filter((entry) => entry.outcome === "unresolved")
|
|
1023
|
+
.map((entry) => entry.detail) ?? [])
|
|
1024
|
+
])
|
|
1025
|
+
.filter((detail) => detail.trim().length > 0)
|
|
1026
|
+
.map((detail) => containsPrivateReferenceMaterial(detail, privateSources, after.commit)
|
|
1027
|
+
? "The prior specification lacks a supported, unambiguous statement of the supplied behavioral scope; restate its exact eligibility and preservation boundaries."
|
|
1028
|
+
: detail);
|
|
1029
|
+
previousVisible = visible;
|
|
1030
|
+
}
|
|
1031
|
+
return yield* contextFailure("reference-grounded specification exhausted its bounded review loop");
|
|
1032
|
+
});
|
|
1033
|
+
const contractFactsBoundary = (evaluate, detail) => Effect.try({ try: evaluate, catch: () => contextFailure(detail) });
|
|
1034
|
+
const requireContractFacts = (condition) => {
|
|
1035
|
+
if (!condition)
|
|
1036
|
+
throw new Error("invalid contract-fact evidence");
|
|
1037
|
+
};
|
|
1038
|
+
const sameContractFactIds = (left, right) => left.length === right.length &&
|
|
1039
|
+
new Set(left).size === left.length &&
|
|
1040
|
+
left.every((id) => right.includes(id));
|
|
1041
|
+
const contractFactsArePrivate = (value, sources, referenceCommit) => containsPrivateReferenceMaterial(value, sources, referenceCommit) ||
|
|
1042
|
+
JSON.stringify(value).includes("private-contract-fact-question-") ||
|
|
1043
|
+
JSON.stringify(value).includes("```");
|
|
1044
|
+
const prepareContractFacts = (input) => {
|
|
1045
|
+
const proposal = parseRepositorySpecificationContractFactsProposalV1(input.value);
|
|
1046
|
+
requireContractFacts(proposal.facts.every((fact) => fact.evidence.every((entry) => referenceEvidenceValid(entry, input.sources)) &&
|
|
1047
|
+
fact.evidence.some((entry) => referenceEvidenceValid(entry, input.sources, "after"))));
|
|
1048
|
+
const scope = repositorySpecificationContractFactsScopeV1(input.originalScope, proposal);
|
|
1049
|
+
const packet = repositorySpecificationContractFactsPacketV1(scope, proposal);
|
|
1050
|
+
requireContractFacts(!contractFactsArePrivate(packet, input.sources, input.referenceCommit));
|
|
1051
|
+
return { proposal, scope, packet };
|
|
1052
|
+
};
|
|
1053
|
+
/**
|
|
1054
|
+
* Mechanical completeness and identity checks do not prove semantic truth.
|
|
1055
|
+
* The reference critic must independently establish it from the pinned source.
|
|
1056
|
+
*/
|
|
1057
|
+
const checkContractFactReview = (input) => {
|
|
1058
|
+
const { review, packet } = input;
|
|
1059
|
+
const scopeIds = input.scope.clauses.map((clause) => clause.id);
|
|
1060
|
+
requireContractFacts(review.packetDigest === packet.digest &&
|
|
1061
|
+
sameContractFactIds(review.scopeChecks.map((check) => check.scopeId), scopeIds) &&
|
|
1062
|
+
review.clarificationRequests.length <=
|
|
1063
|
+
REPOSITORY_SPECIFICATION_CONTRACT_FACTS_MAXIMUM_QUESTIONS);
|
|
1064
|
+
for (const check of review.scopeChecks) {
|
|
1065
|
+
requireContractFacts(sameContractFactIds(check.factIds, packet.facts.filter((fact) => fact.scopeId === check.scopeId).map((fact) => fact.id)) &&
|
|
1066
|
+
check.detail.trim().length > 0 &&
|
|
1067
|
+
check.detail.length <= 600 &&
|
|
1068
|
+
check.evidence.length <= 8 &&
|
|
1069
|
+
(input.perspective === "solver"
|
|
1070
|
+
? check.evidence.length === 0
|
|
1071
|
+
: (check.outcome !== "complete" || check.evidence.length > 0) &&
|
|
1072
|
+
check.evidence.every((entry) => referenceEvidenceValid(entry, input.sources, "after"))) &&
|
|
1073
|
+
(check.outcome === "complete" ||
|
|
1074
|
+
review.clarificationRequests.some((question) => question.scopeId === check.scopeId)));
|
|
1075
|
+
}
|
|
1076
|
+
const questionKeys = review.clarificationRequests.map((question) => JSON.stringify(question));
|
|
1077
|
+
requireContractFacts(new Set(questionKeys).size === questionKeys.length);
|
|
1078
|
+
for (const question of review.clarificationRequests) {
|
|
1079
|
+
requireContractFacts(scopeIds.includes(question.scopeId) &&
|
|
1080
|
+
question.question.trim().length > 0 &&
|
|
1081
|
+
question.question.length <= 800 &&
|
|
1082
|
+
new Set(question.factIds).size === question.factIds.length &&
|
|
1083
|
+
question.factIds.every((id) => packet.facts.some((fact) => fact.id === id && fact.scopeId === question.scopeId)) &&
|
|
1084
|
+
review.scopeChecks.some((check) => check.scopeId === question.scopeId && check.outcome !== "complete"));
|
|
1085
|
+
}
|
|
1086
|
+
requireContractFacts(!contractFactsArePrivate({
|
|
1087
|
+
details: review.scopeChecks.map((check) => check.detail),
|
|
1088
|
+
questions: review.clarificationRequests
|
|
1089
|
+
}, input.sources, input.referenceCommit));
|
|
1090
|
+
return review.scopeChecks
|
|
1091
|
+
.filter((check) => check.outcome !== "complete")
|
|
1092
|
+
.map((check) => `The independent ${input.perspective} contract-fact check for ${check.scopeId} is ${check.outcome}: ${check.detail}`);
|
|
1093
|
+
};
|
|
1094
|
+
const contractFactClarificationRequests = (reviews, sequence) => {
|
|
1095
|
+
const questions = reviews.flatMap((review) => review.contractFactReview.clarificationRequests);
|
|
1096
|
+
const unique = questions.filter((question, index) => questions.findIndex((other) => other.scopeId === question.scopeId &&
|
|
1097
|
+
other.reason === question.reason &&
|
|
1098
|
+
other.question === question.question &&
|
|
1099
|
+
sameContractFactIds(other.factIds, question.factIds)) === index);
|
|
1100
|
+
requireContractFacts(unique.length <= REPOSITORY_SPECIFICATION_CONTRACT_FACTS_MAXIMUM_QUESTIONS);
|
|
1101
|
+
return unique.map((question, index) => ({
|
|
1102
|
+
requestId: `private-contract-fact-question-${String(sequence)}-${String(index + 1)}`,
|
|
1103
|
+
scopeId: question.scopeId,
|
|
1104
|
+
factIds: [...question.factIds],
|
|
1105
|
+
reason: question.reason,
|
|
1106
|
+
question: question.question
|
|
1107
|
+
}));
|
|
1108
|
+
};
|
|
1109
|
+
const validateContractFactClarification = (input) => {
|
|
1110
|
+
requireContractFacts(sameContractFactIds(input.clarification.resolutions.map((resolution) => resolution.requestId), input.requests.map((request) => request.requestId)));
|
|
1111
|
+
const affectedScopes = new Set(input.requests.map((request) => request.scopeId));
|
|
1112
|
+
// A missing-fact repair cannot change unrelated scopes or silently remove their
|
|
1113
|
+
// facts. The independent reference review rechecks the whole replacement.
|
|
1114
|
+
for (const previous of input.previous.facts.filter((fact) => !affectedScopes.has(fact.scopeId))) {
|
|
1115
|
+
requireContractFacts(JSON.stringify(input.next.facts.find((fact) => fact.id === previous.id)) ===
|
|
1116
|
+
JSON.stringify(previous));
|
|
1117
|
+
}
|
|
1118
|
+
for (const next of input.next.facts.filter((fact) => !affectedScopes.has(fact.scopeId))) {
|
|
1119
|
+
requireContractFacts(JSON.stringify(input.previous.facts.find((fact) => fact.id === next.id)) ===
|
|
1120
|
+
JSON.stringify(next));
|
|
1121
|
+
}
|
|
1122
|
+
for (const resolution of input.clarification.resolutions) {
|
|
1123
|
+
const request = input.requests.find((entry) => entry.requestId === resolution.requestId);
|
|
1124
|
+
requireContractFacts(resolution.outcome === "answered" &&
|
|
1125
|
+
resolution.detail.trim().length > 0 &&
|
|
1126
|
+
resolution.detail.length <= 800 &&
|
|
1127
|
+
resolution.factIds.length > 0 &&
|
|
1128
|
+
new Set(resolution.factIds).size === resolution.factIds.length &&
|
|
1129
|
+
resolution.factIds.every((id) => input.next.facts.some((fact) => fact.id === id && fact.scopeId === request.scopeId)));
|
|
1130
|
+
}
|
|
1131
|
+
};
|
|
1132
|
+
const markedReviewWithFailures = (review, call, reviewerKind, failures) => ({
|
|
1133
|
+
...review,
|
|
1134
|
+
reviewerId: call.operationId,
|
|
1135
|
+
reviewerKind,
|
|
1136
|
+
independentlyProduced: true,
|
|
1137
|
+
...(failures.length === 0
|
|
1138
|
+
? {}
|
|
1139
|
+
: {
|
|
1140
|
+
verdict: "insufficient",
|
|
1141
|
+
detail: [review.detail, ...failures].join(" "),
|
|
1142
|
+
findings: [
|
|
1143
|
+
...review.findings,
|
|
1144
|
+
...failures.map((detail) => ({
|
|
1145
|
+
axis: "unsupported-assumption",
|
|
1146
|
+
severity: "blocker",
|
|
1147
|
+
detail
|
|
1148
|
+
}))
|
|
1149
|
+
]
|
|
1150
|
+
})
|
|
1151
|
+
});
|
|
1152
|
+
const authorContractFactsSpecification = Effect.fn("CaseAuthoring.authorContractFacts")(function* (input) {
|
|
1153
|
+
const languageModel = yield* RepositoryFoundryLanguageModel;
|
|
1154
|
+
const request = input.request;
|
|
1155
|
+
const maximumRevisions = request.maximumSpecificationRevisions;
|
|
1156
|
+
const originalScope = input.analysis.referenceScope;
|
|
1157
|
+
const originalBehavioralScope = originalScope.clauses.map((clause) => ({
|
|
1158
|
+
id: clause.id,
|
|
1159
|
+
kind: clause.kind,
|
|
1160
|
+
behaviorIds: clause.behaviorIds,
|
|
1161
|
+
description: clause.description
|
|
1162
|
+
}));
|
|
1163
|
+
const pendingQuestions = originalScope.unresolvedQuestions.map((question, index) => ({
|
|
1164
|
+
id: `private-reference-question-${String(index + 1)}`,
|
|
1165
|
+
question
|
|
1166
|
+
}));
|
|
1167
|
+
const dimensionContext = request.requestedDimension === undefined
|
|
1168
|
+
? {}
|
|
1169
|
+
: { requestedDimension: request.requestedDimension };
|
|
1170
|
+
const privateReferenceEvidence = {
|
|
1171
|
+
beforeCommit: input.before.commit,
|
|
1172
|
+
referenceCommit: input.after.commit,
|
|
1173
|
+
sources: input.privateSources,
|
|
1174
|
+
pendingQuestions
|
|
1175
|
+
};
|
|
1176
|
+
let current = yield* contractFactsBoundary(() => prepareContractFacts({
|
|
1177
|
+
value: input.analysis.contractFacts,
|
|
1178
|
+
originalScope,
|
|
1179
|
+
sources: input.privateSources,
|
|
1180
|
+
referenceCommit: input.after.commit
|
|
1181
|
+
}), "contract-fact proposal is malformed, ungrounded, oversized, or contains private material");
|
|
1182
|
+
let analystOperationId = input.analystCall.operationId;
|
|
1183
|
+
let clarificationRequests = [];
|
|
1184
|
+
let previousVisible;
|
|
1185
|
+
let revisionFeedback = [];
|
|
1186
|
+
const modelCalls = [input.analystCall];
|
|
1187
|
+
const history = [];
|
|
1188
|
+
const factsHistory = [];
|
|
1189
|
+
for (let sequence = 0; sequence <= maximumRevisions; sequence += 1) {
|
|
1190
|
+
const operationPrefix = sequence === 0
|
|
1191
|
+
? request.operationId
|
|
1192
|
+
: `${request.operationId}:specification-revision:${String(sequence)}`;
|
|
1193
|
+
const answeredRequestIds = sequence === 0 ? [] : clarificationRequests.map((question) => question.requestId);
|
|
1194
|
+
if (sequence > 0 && clarificationRequests.length > 0) {
|
|
1195
|
+
// The plan reserves at most one existing-role analyst call per revision,
|
|
1196
|
+
// not one call per question and never another retry/continuation owner.
|
|
1197
|
+
const clarificationInput = {
|
|
1198
|
+
...dimensionContext,
|
|
1199
|
+
targetBehavior: request.seed.targetBehavior,
|
|
1200
|
+
behavioralScope: originalBehavioralScope,
|
|
1201
|
+
contractFacts: current.packet,
|
|
1202
|
+
privateContractFacts: current.proposal,
|
|
1203
|
+
clarificationRequests,
|
|
1204
|
+
previousVisible,
|
|
1205
|
+
privateReferenceEvidence
|
|
1206
|
+
};
|
|
1207
|
+
yield* assertBoundedReferenceInput(clarificationInput);
|
|
1208
|
+
const clarified = yield* languageModel.generateStructured({
|
|
1209
|
+
plan: request.modelPlan,
|
|
1210
|
+
role: "repository-analyst",
|
|
1211
|
+
operationId: `${operationPrefix}:contract-facts-analyst`,
|
|
1212
|
+
instructions: CONTRACT_FACTS_CLARIFICATION_INSTRUCTIONS,
|
|
1213
|
+
input: clarificationInput,
|
|
1214
|
+
schemaName: "routekit_repository_contract_fact_clarification_v1",
|
|
1215
|
+
outputSchema: RepositorySpecificationContractFactClarificationV1,
|
|
1216
|
+
maximumOutputTokens: repositoryFoundryRoleOutputCeilingV1("repository-analyst")
|
|
1217
|
+
});
|
|
1218
|
+
modelCalls.push(clarified.call);
|
|
1219
|
+
const next = yield* contractFactsBoundary(() => {
|
|
1220
|
+
const prepared = prepareContractFacts({
|
|
1221
|
+
value: { version: clarified.value.version, facts: clarified.value.facts },
|
|
1222
|
+
originalScope,
|
|
1223
|
+
sources: input.privateSources,
|
|
1224
|
+
referenceCommit: input.after.commit
|
|
1225
|
+
});
|
|
1226
|
+
validateContractFactClarification({
|
|
1227
|
+
clarification: clarified.value,
|
|
1228
|
+
requests: clarificationRequests,
|
|
1229
|
+
previous: current.proposal,
|
|
1230
|
+
next: prepared.proposal
|
|
1231
|
+
});
|
|
1232
|
+
return prepared;
|
|
1233
|
+
}, "contract-fact clarification is unresolved, malformed, ungrounded, or changes unrelated scope");
|
|
1234
|
+
current = next;
|
|
1235
|
+
analystOperationId = clarified.call.operationId;
|
|
1236
|
+
}
|
|
1237
|
+
const behavioralScope = current.scope.clauses.map((clause) => ({
|
|
1238
|
+
id: clause.id,
|
|
1239
|
+
kind: clause.kind,
|
|
1240
|
+
behaviorIds: clause.behaviorIds,
|
|
1241
|
+
description: clause.description
|
|
1242
|
+
}));
|
|
1243
|
+
const groundedTargetBehavior = request.seed.targetBehavior.map((behavior) => ({
|
|
1244
|
+
...behavior,
|
|
1245
|
+
description: current.scope.clauses
|
|
1246
|
+
.filter((clause) => clause.behaviorIds.includes(behavior.id))
|
|
1247
|
+
.map((clause) => clause.description)
|
|
1248
|
+
.join(" ")
|
|
1249
|
+
}));
|
|
1250
|
+
const publicContext = {
|
|
1251
|
+
...dimensionContext,
|
|
1252
|
+
targetBehavior: groundedTargetBehavior,
|
|
1253
|
+
analysis: input.publicAnalysis,
|
|
1254
|
+
behavioralScope,
|
|
1255
|
+
family: input.familyContext,
|
|
1256
|
+
contractFacts: current.packet
|
|
1257
|
+
};
|
|
1258
|
+
const writerInput = {
|
|
1259
|
+
...publicContext,
|
|
1260
|
+
initialCommit: input.before.commit,
|
|
1261
|
+
selectedRepositoryContext: input.contextSources,
|
|
1262
|
+
...(sequence === 0 ? {} : { previousVisible, behavioralReviewFeedback: revisionFeedback })
|
|
1263
|
+
};
|
|
1264
|
+
yield* assertBoundedReferenceInput(writerInput);
|
|
1265
|
+
const authored = yield* languageModel.generateStructured({
|
|
1266
|
+
plan: request.modelPlan,
|
|
1267
|
+
role: "specification-writer",
|
|
1268
|
+
operationId: `${operationPrefix}:specification-writer`,
|
|
1269
|
+
instructions: `${SPECIFICATION_INSTRUCTIONS}\n\n${CONTRACT_FACTS_WRITER_INSTRUCTIONS}${sequence === 0 ? "" : `\n${SPECIFICATION_REVISION_INSTRUCTIONS}`}`,
|
|
1270
|
+
input: writerInput,
|
|
1271
|
+
schemaName: "routekit_repository_specification_v1",
|
|
1272
|
+
outputSchema: RepositorySpecificationOutput,
|
|
1273
|
+
maximumOutputTokens: repositoryFoundryRoleOutputCeilingV1("specification-writer")
|
|
1274
|
+
});
|
|
1275
|
+
modelCalls.push(authored.call);
|
|
1276
|
+
const visible = {
|
|
1277
|
+
lane: "repository-agent",
|
|
1278
|
+
id: request.caseId,
|
|
1279
|
+
requestText: authored.value.requestText,
|
|
1280
|
+
checkoutCommit: input.before.commit,
|
|
1281
|
+
allowedTools: ["read", "search", "edit", "shell", "test"],
|
|
1282
|
+
constraints: [
|
|
1283
|
+
...new Set([
|
|
1284
|
+
...authored.value.constraints,
|
|
1285
|
+
...current.packet.facts.map(renderRepositorySpecificationContractFactV1),
|
|
1286
|
+
"Do not weaken or delete tests to make the task pass.",
|
|
1287
|
+
"Preserve unrelated public behavior."
|
|
1288
|
+
])
|
|
1289
|
+
]
|
|
1290
|
+
};
|
|
1291
|
+
if (contractFactsArePrivate(visible, input.privateSources, input.after.commit)) {
|
|
1292
|
+
return yield* contextFailure("private material leaked into the marked visible specification");
|
|
1293
|
+
}
|
|
1294
|
+
const reviewInput = {
|
|
1295
|
+
...publicContext,
|
|
1296
|
+
visible,
|
|
1297
|
+
initialRepositoryExcerpts: input.contextSources
|
|
1298
|
+
};
|
|
1299
|
+
const privateReviewInput = {
|
|
1300
|
+
...reviewInput,
|
|
1301
|
+
privateReferenceEvidence,
|
|
1302
|
+
privateContractFacts: current.proposal
|
|
1303
|
+
};
|
|
1304
|
+
yield* assertBoundedReferenceInput(privateReviewInput);
|
|
1305
|
+
const [criticA, criticB] = yield* Effect.all([
|
|
1306
|
+
languageModel.generateStructured({
|
|
1307
|
+
plan: request.modelPlan,
|
|
1308
|
+
role: "specification-critic-a",
|
|
1309
|
+
operationId: `${operationPrefix}:specification-critic-a`,
|
|
1310
|
+
instructions: `${criticInstructions("solver")}\n\n${CONTRACT_FACTS_REVIEW_INSTRUCTIONS}\nYou remain blind to the reference. Return empty evidence arrays in every contractFactReview.scopeChecks record; evaluate the actual visible contract and supplied pre-change context.`,
|
|
1311
|
+
input: reviewInput,
|
|
1312
|
+
schemaName: "routekit_repository_specification_facts_review_v1",
|
|
1313
|
+
outputSchema: RepositoryContractFactsReviewOutput,
|
|
1314
|
+
maximumOutputTokens: repositoryFoundryRoleOutputCeilingV1("specification-critic-a")
|
|
1315
|
+
}),
|
|
1316
|
+
languageModel.generateStructured({
|
|
1317
|
+
plan: request.modelPlan,
|
|
1318
|
+
role: "specification-critic-b",
|
|
1319
|
+
operationId: `${operationPrefix}:specification-critic-b`,
|
|
1320
|
+
instructions: `${criticInstructions("ambiguity")}\n\n${REFERENCE_CRITIC_INSTRUCTIONS}\n\n${CONTRACT_FACTS_REVIEW_INSTRUCTIONS}\n\n${CONTRACT_FACTS_REFERENCE_REVIEW_INSTRUCTIONS}`,
|
|
1321
|
+
input: privateReviewInput,
|
|
1322
|
+
schemaName: "routekit_repository_specification_facts_review_v1",
|
|
1323
|
+
outputSchema: RepositoryContractFactsReviewOutput,
|
|
1324
|
+
maximumOutputTokens: repositoryFoundryRoleOutputCeilingV1("specification-critic-b")
|
|
1325
|
+
})
|
|
1326
|
+
], { concurrency: 2 });
|
|
1327
|
+
modelCalls.push(criticA.call, criticB.call);
|
|
1328
|
+
const factFailures = yield* contractFactsBoundary(() => [criticA, criticB].map((critic, index) => checkContractFactReview({
|
|
1329
|
+
review: critic.value.contractFactReview,
|
|
1330
|
+
packet: current.packet,
|
|
1331
|
+
scope: current.scope,
|
|
1332
|
+
sources: input.privateSources,
|
|
1333
|
+
referenceCommit: input.after.commit,
|
|
1334
|
+
perspective: index === 0 ? "solver" : "reference"
|
|
1335
|
+
})), "contract-fact review has stale identity, incomplete evidence, malformed questions, or private material");
|
|
1336
|
+
const compatibilityFailures = referenceCompatibilityFailures(criticB.value, current.scope, input.privateSources, pendingQuestions, visible);
|
|
1337
|
+
const reviews = [
|
|
1338
|
+
markedReviewWithFailures(criticA.value, criticA.call, "independent-solver", factFailures[0]),
|
|
1339
|
+
markedReviewWithFailures(criticB.value, criticB.call, "model-critic", [
|
|
1340
|
+
...factFailures[1],
|
|
1341
|
+
...compatibilityFailures
|
|
1342
|
+
])
|
|
1343
|
+
];
|
|
1344
|
+
const critique = yield* critiqueRepositoryTaskSpecificationV1({
|
|
1345
|
+
repositoryRoot: request.repositoryRoot,
|
|
1346
|
+
seed: { ...request.seed, targetBehavior: groundedTargetBehavior },
|
|
1347
|
+
family: request.family,
|
|
1348
|
+
visible,
|
|
1349
|
+
reviews,
|
|
1350
|
+
...dimensionContext
|
|
1351
|
+
});
|
|
1352
|
+
history.push({
|
|
1353
|
+
sequence,
|
|
1354
|
+
visible,
|
|
1355
|
+
reviews,
|
|
1356
|
+
rejectionReasons: critique.rejectionReasons,
|
|
1357
|
+
contractFactsDigest: current.packet.digest
|
|
1358
|
+
});
|
|
1359
|
+
factsHistory.push({
|
|
1360
|
+
sequence,
|
|
1361
|
+
packetDigest: current.packet.digest,
|
|
1362
|
+
analystOperationId,
|
|
1363
|
+
clarificationRequestIds: answeredRequestIds
|
|
1364
|
+
});
|
|
1365
|
+
if (critique.outcome === "pass") {
|
|
1366
|
+
return {
|
|
1367
|
+
version: 1,
|
|
1368
|
+
caseId: request.caseId,
|
|
1369
|
+
analysis: input.analysis,
|
|
1370
|
+
contextSources: input.contextSources,
|
|
1371
|
+
visible,
|
|
1372
|
+
reviews,
|
|
1373
|
+
modelCalls,
|
|
1374
|
+
groundedTargetBehavior,
|
|
1375
|
+
referenceGrounding: {
|
|
1376
|
+
beforeCommit: input.before.commit,
|
|
1377
|
+
referenceCommit: input.after.commit,
|
|
1378
|
+
sources: input.privateSources,
|
|
1379
|
+
scope: current.scope
|
|
1380
|
+
},
|
|
1381
|
+
specificationRevisions: history,
|
|
1382
|
+
contractFacts: {
|
|
1383
|
+
version: 1,
|
|
1384
|
+
packet: current.packet,
|
|
1385
|
+
independentlyReviewed: true,
|
|
1386
|
+
reviewerOperationIds: [criticA.call.operationId, criticB.call.operationId],
|
|
1387
|
+
history: factsHistory
|
|
1388
|
+
}
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
if (factFailures.every((failures) => failures.length === 0) &&
|
|
1392
|
+
hasIndependentGroundedDimensionMismatch({
|
|
1393
|
+
...dimensionContext,
|
|
1394
|
+
operationPrefix,
|
|
1395
|
+
before: input.before,
|
|
1396
|
+
targetBehavior: groundedTargetBehavior,
|
|
1397
|
+
reviews,
|
|
1398
|
+
scope: current.scope,
|
|
1399
|
+
sources: input.privateSources
|
|
1400
|
+
})) {
|
|
1401
|
+
return yield* new RepositoryFoundryError({
|
|
1402
|
+
operation: "select-generation-context",
|
|
1403
|
+
detail: "generated specification cannot assess the pinned requested dimension: two independent critics established a definite mismatch with complete grounded scope and contract-fact evidence",
|
|
1404
|
+
generationRejection: {
|
|
1405
|
+
code: "specification-dimension-mismatch",
|
|
1406
|
+
completedRevisions: sequence
|
|
1407
|
+
}
|
|
1408
|
+
});
|
|
1409
|
+
}
|
|
1410
|
+
if (sequence === maximumRevisions) {
|
|
1411
|
+
const publicReasons = critique.rejectionReasons.map((detail) => contractFactsArePrivate(detail, input.privateSources, input.after.commit)
|
|
1412
|
+
? "A private reference compatibility finding blocks this specification."
|
|
1413
|
+
: detail);
|
|
1414
|
+
return yield* new RepositoryFoundryError({
|
|
1415
|
+
operation: "select-generation-context",
|
|
1416
|
+
detail: `generated specification failed independent review after ${String(sequence)} bounded revisions: ${publicReasons.join("; ")}`,
|
|
1417
|
+
generationRejection: {
|
|
1418
|
+
code: "specification-review-exhausted",
|
|
1419
|
+
completedRevisions: sequence
|
|
1420
|
+
}
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
clarificationRequests = yield* contractFactsBoundary(() => contractFactClarificationRequests([criticA.value, criticB.value], sequence), "contract-fact clarification requests exceed their immutable per-revision bound");
|
|
1424
|
+
revisionFeedback = reviews
|
|
1425
|
+
.flatMap((review) => [
|
|
1426
|
+
review.detail,
|
|
1427
|
+
...(review.dimensionFit === undefined ? [] : [review.dimensionFit.detail]),
|
|
1428
|
+
...review.findings.map((finding) => finding.detail),
|
|
1429
|
+
...(review.criticalBehaviorCoverage
|
|
1430
|
+
?.filter((entry) => entry.outcome !== "covered")
|
|
1431
|
+
.map((entry) => entry.detail) ?? []),
|
|
1432
|
+
...(review.referenceCompatibility?.scopeCoverage
|
|
1433
|
+
.filter((entry) => entry.outcome !== "supported")
|
|
1434
|
+
.map((entry) => entry.detail) ?? []),
|
|
1435
|
+
...(review.referenceCompatibility?.questionResolutions
|
|
1436
|
+
?.filter((entry) => entry.outcome === "unresolved")
|
|
1437
|
+
.map((entry) => entry.detail) ?? []),
|
|
1438
|
+
...(review.contractFactReview?.scopeChecks
|
|
1439
|
+
.filter((check) => check.outcome !== "complete")
|
|
1440
|
+
.map((check) => check.detail) ?? [])
|
|
1441
|
+
])
|
|
1442
|
+
.filter((detail) => detail.trim().length > 0)
|
|
1443
|
+
.map((detail) => contractFactsArePrivate(detail, input.privateSources, input.after.commit)
|
|
1444
|
+
? "Resolve the remaining behavioral finding using only the supplied public contract facts."
|
|
1445
|
+
: detail);
|
|
1446
|
+
previousVisible = visible;
|
|
1447
|
+
}
|
|
1448
|
+
return yield* contextFailure("marked contract-fact authoring exhausted its bounded review loop");
|
|
1449
|
+
});
|
|
1450
|
+
export const makeCaseAuthoring = Effect.gen(function* () {
|
|
1451
|
+
const languageModel = yield* RepositoryFoundryLanguageModel;
|
|
1452
|
+
return CaseAuthoring.of({
|
|
1453
|
+
authorSpecification: (input) => authorRepositoryCaseSpecificationV1(input).pipe(Effect.provideService(RepositoryFoundryLanguageModel, languageModel))
|
|
1454
|
+
});
|
|
1455
|
+
});
|
|
1456
|
+
export const CaseAuthoringLive = Layer.effect(CaseAuthoring, makeCaseAuthoring);
|