@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,513 @@
|
|
|
1
|
+
export const EVAL_SOURCE_RETRIEVAL_INDEX_FILES = 512;
|
|
2
|
+
export const EVAL_SOURCE_RETRIEVAL_INDEX_BYTES = 8 * 1024 * 1024;
|
|
3
|
+
export const EVAL_SOURCE_RETRIEVAL_FILE_BYTES = 256 * 1024;
|
|
4
|
+
export const EVAL_SOURCE_RETRIEVAL_PACKET_BLOCKS = 20;
|
|
5
|
+
export const EVAL_SOURCE_RETRIEVAL_BLOCKS_PER_SOURCE = 2;
|
|
6
|
+
const STOP_WORDS = new Set([
|
|
7
|
+
"about",
|
|
8
|
+
"after",
|
|
9
|
+
"and",
|
|
10
|
+
"are",
|
|
11
|
+
"been",
|
|
12
|
+
"for",
|
|
13
|
+
"from",
|
|
14
|
+
"has",
|
|
15
|
+
"into",
|
|
16
|
+
"request",
|
|
17
|
+
"requests",
|
|
18
|
+
"that",
|
|
19
|
+
"the",
|
|
20
|
+
"this",
|
|
21
|
+
"with"
|
|
22
|
+
]);
|
|
23
|
+
const canonicalCompare = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
24
|
+
const alphaNumeric = (character) => {
|
|
25
|
+
const code = character.codePointAt(0);
|
|
26
|
+
return (code !== undefined &&
|
|
27
|
+
((code >= 48 && code <= 57) ||
|
|
28
|
+
(code >= 65 && code <= 90) ||
|
|
29
|
+
(code >= 97 && code <= 122)));
|
|
30
|
+
};
|
|
31
|
+
const upper = (character) => {
|
|
32
|
+
const code = character.codePointAt(0);
|
|
33
|
+
return code !== undefined && code >= 65 && code <= 90;
|
|
34
|
+
};
|
|
35
|
+
const lowerOrNumber = (character) => {
|
|
36
|
+
const code = character.codePointAt(0);
|
|
37
|
+
return (code !== undefined &&
|
|
38
|
+
((code >= 48 && code <= 57) || (code >= 97 && code <= 122)));
|
|
39
|
+
};
|
|
40
|
+
const normalizeToken = (value) => {
|
|
41
|
+
const lower = value.toLowerCase();
|
|
42
|
+
if (lower.length >= 5 && lower.endsWith("ies")) {
|
|
43
|
+
return `${lower.slice(0, -3)}y`;
|
|
44
|
+
}
|
|
45
|
+
if (lower.length >= 5 &&
|
|
46
|
+
lower.endsWith("s") &&
|
|
47
|
+
!lower.endsWith("ss") &&
|
|
48
|
+
!lower.endsWith("us") &&
|
|
49
|
+
!lower.endsWith("is")) {
|
|
50
|
+
return lower.slice(0, -1);
|
|
51
|
+
}
|
|
52
|
+
return lower;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Tokenizes identifiers and prose without asking a model to infer source
|
|
56
|
+
* relevance. CamelCase boundaries are retained so `providerBackend` can match
|
|
57
|
+
* the reviewed positive scope `provider backend`.
|
|
58
|
+
*/
|
|
59
|
+
export const evaluationSourceTokens = (value) => {
|
|
60
|
+
const tokens = [];
|
|
61
|
+
let token = "";
|
|
62
|
+
const flush = () => {
|
|
63
|
+
const normalized = normalizeToken(token);
|
|
64
|
+
token = "";
|
|
65
|
+
if (normalized.length >= 3 && !STOP_WORDS.has(normalized)) {
|
|
66
|
+
tokens.push(normalized);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const characters = [...value];
|
|
70
|
+
for (const [index, character] of characters.entries()) {
|
|
71
|
+
if (!alphaNumeric(character)) {
|
|
72
|
+
flush();
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const previous = token.at(-1);
|
|
76
|
+
const next = characters[index + 1];
|
|
77
|
+
if (token.length > 0 &&
|
|
78
|
+
previous !== undefined &&
|
|
79
|
+
upper(character) &&
|
|
80
|
+
(lowerOrNumber(previous) ||
|
|
81
|
+
(upper(previous) && next !== undefined && lowerOrNumber(next)))) {
|
|
82
|
+
flush();
|
|
83
|
+
}
|
|
84
|
+
token += character;
|
|
85
|
+
}
|
|
86
|
+
flush();
|
|
87
|
+
return tokens;
|
|
88
|
+
};
|
|
89
|
+
const positiveQueryTerms = (input) => {
|
|
90
|
+
const dimensions = input.targetDimensions ?? [];
|
|
91
|
+
const values = dimensions.length === 0
|
|
92
|
+
? [input.workloadDescription ?? ""]
|
|
93
|
+
: dimensions.flatMap((dimension) => [
|
|
94
|
+
dimension.id,
|
|
95
|
+
dimension.description,
|
|
96
|
+
...dimension.includes
|
|
97
|
+
]);
|
|
98
|
+
return [...new Set(values.flatMap(evaluationSourceTokens))].sort(canonicalCompare);
|
|
99
|
+
};
|
|
100
|
+
const positiveQueryFacets = (dimensions) => dimensions.flatMap((dimension) => {
|
|
101
|
+
const includes = dimension.includes
|
|
102
|
+
.map((value, index) => ({
|
|
103
|
+
label: `${dimension.id} include ${String(index + 1)}`,
|
|
104
|
+
terms: [...new Set(evaluationSourceTokens(value))].sort(canonicalCompare)
|
|
105
|
+
}))
|
|
106
|
+
.filter((facet) => facet.terms.length > 0);
|
|
107
|
+
return includes.length > 0
|
|
108
|
+
? includes
|
|
109
|
+
: [
|
|
110
|
+
{
|
|
111
|
+
label: dimension.id,
|
|
112
|
+
terms: [
|
|
113
|
+
...new Set(evaluationSourceTokens(`${dimension.id} ${dimension.description}`))
|
|
114
|
+
].sort(canonicalCompare)
|
|
115
|
+
}
|
|
116
|
+
];
|
|
117
|
+
});
|
|
118
|
+
const ownershipRoot = (path) => {
|
|
119
|
+
const segments = path.split("/");
|
|
120
|
+
const first = segments[0] ?? path;
|
|
121
|
+
if (["apps", "packages", "services", "tooling"].includes(first) &&
|
|
122
|
+
segments[1] !== undefined) {
|
|
123
|
+
return `${first}/${segments[1]}`;
|
|
124
|
+
}
|
|
125
|
+
return first;
|
|
126
|
+
};
|
|
127
|
+
const retrievalScope = (path) => {
|
|
128
|
+
const segments = path.split("/");
|
|
129
|
+
if (["apps", "packages", "services", "tooling"].includes(segments[0] ?? "") &&
|
|
130
|
+
segments[1] !== undefined &&
|
|
131
|
+
segments[2] === "src" &&
|
|
132
|
+
segments[3] !== undefined) {
|
|
133
|
+
return segments.slice(0, 4).join("/");
|
|
134
|
+
}
|
|
135
|
+
return undefined;
|
|
136
|
+
};
|
|
137
|
+
const frequencies = (tokens) => {
|
|
138
|
+
const values = new Map();
|
|
139
|
+
for (const token of tokens) {
|
|
140
|
+
values.set(token, (values.get(token) ?? 0) + 1);
|
|
141
|
+
}
|
|
142
|
+
return values;
|
|
143
|
+
};
|
|
144
|
+
const bm25 = (input) => {
|
|
145
|
+
if (input.termFrequency === 0)
|
|
146
|
+
return 0;
|
|
147
|
+
const k1 = 1.2;
|
|
148
|
+
const b = 0.75;
|
|
149
|
+
const normalizedLength = input.averageLength <= 0 ? 1 : input.length / input.averageLength;
|
|
150
|
+
return ((input.termFrequency * (k1 + 1)) /
|
|
151
|
+
(input.termFrequency + k1 * (1 - b + b * normalizedLength)));
|
|
152
|
+
};
|
|
153
|
+
const pathRanks = (candidates, queryTerms) => {
|
|
154
|
+
const tokenized = candidates.map((candidate) => ({
|
|
155
|
+
candidate,
|
|
156
|
+
tokens: evaluationSourceTokens(candidate.path)
|
|
157
|
+
}));
|
|
158
|
+
const averageLength = tokenized.reduce((total, item) => total + item.tokens.length, 0) /
|
|
159
|
+
Math.max(1, tokenized.length);
|
|
160
|
+
const documentFrequency = new Map(queryTerms.map((term) => [
|
|
161
|
+
term,
|
|
162
|
+
tokenized.filter((item) => item.tokens.includes(term)).length
|
|
163
|
+
]));
|
|
164
|
+
return tokenized
|
|
165
|
+
.map(({ candidate, tokens }) => {
|
|
166
|
+
const counts = frequencies(tokens);
|
|
167
|
+
const matchedTerms = queryTerms.filter((term) => (counts.get(term) ?? 0) > 0);
|
|
168
|
+
const score = matchedTerms.reduce((total, term) => {
|
|
169
|
+
const frequency = documentFrequency.get(term) ?? 0;
|
|
170
|
+
const inverseDocumentFrequency = Math.log(1 +
|
|
171
|
+
(tokenized.length - frequency + 0.5) /
|
|
172
|
+
(frequency + 0.5));
|
|
173
|
+
return (total +
|
|
174
|
+
inverseDocumentFrequency *
|
|
175
|
+
bm25({
|
|
176
|
+
termFrequency: counts.get(term) ?? 0,
|
|
177
|
+
length: tokens.length,
|
|
178
|
+
averageLength
|
|
179
|
+
}));
|
|
180
|
+
}, 0);
|
|
181
|
+
return { candidate, score, matchedTerms };
|
|
182
|
+
})
|
|
183
|
+
.sort((left, right) => right.score - left.score ||
|
|
184
|
+
canonicalCompare(left.candidate.path, right.candidate.path));
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* Produces a bounded content-index plan. Positive path matches identify likely
|
|
188
|
+
* ownership roots, then generic filenames inside those roots may compete by
|
|
189
|
+
* content. This avoids reading an unbounded repository or relying on inventory
|
|
190
|
+
* order.
|
|
191
|
+
*/
|
|
192
|
+
export function planEvaluationSourceRetrieval(input) {
|
|
193
|
+
const maximumFiles = input.maximumFiles ?? EVAL_SOURCE_RETRIEVAL_INDEX_FILES;
|
|
194
|
+
const maximumBytes = input.maximumBytes ?? EVAL_SOURCE_RETRIEVAL_INDEX_BYTES;
|
|
195
|
+
const queryTerms = positiveQueryTerms(input);
|
|
196
|
+
const ranked = pathRanks(input.candidates, queryTerms);
|
|
197
|
+
const eligible = ranked.filter((item) => item.candidate.sizeBytes <= EVAL_SOURCE_RETRIEVAL_FILE_BYTES);
|
|
198
|
+
const eligibleBytes = eligible.reduce((total, item) => total + item.candidate.sizeBytes, 0);
|
|
199
|
+
if (eligible.length <= maximumFiles &&
|
|
200
|
+
eligibleBytes <= maximumBytes) {
|
|
201
|
+
const scopeScores = new Map();
|
|
202
|
+
for (const item of eligible) {
|
|
203
|
+
const scope = retrievalScope(item.candidate.path);
|
|
204
|
+
if (scope !== undefined) {
|
|
205
|
+
scopeScores.set(scope, Math.max(scopeScores.get(scope) ?? 0, item.score));
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return eligible
|
|
209
|
+
.map((item) => {
|
|
210
|
+
const scope = retrievalScope(item.candidate.path);
|
|
211
|
+
return {
|
|
212
|
+
...item.candidate,
|
|
213
|
+
pathScore: item.score +
|
|
214
|
+
(scope === undefined ? 0 : scopeScores.get(scope) ?? 0)
|
|
215
|
+
};
|
|
216
|
+
})
|
|
217
|
+
.sort((left, right) => canonicalCompare(left.path, right.path));
|
|
218
|
+
}
|
|
219
|
+
const positivePathMatches = ranked.filter((item) => item.score > 0);
|
|
220
|
+
const scopeScores = new Map();
|
|
221
|
+
for (const item of positivePathMatches) {
|
|
222
|
+
const scope = retrievalScope(item.candidate.path);
|
|
223
|
+
if (scope !== undefined) {
|
|
224
|
+
scopeScores.set(scope, Math.max(scopeScores.get(scope) ?? 0, item.score));
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const explicit = ranked.filter((item) => item.candidate.explicitReason !== undefined);
|
|
228
|
+
const implicatedRoots = new Set(positivePathMatches
|
|
229
|
+
.slice(0, 32)
|
|
230
|
+
.map((item) => ownershipRoot(item.candidate.path)));
|
|
231
|
+
const retrieved = positivePathMatches.length === 0
|
|
232
|
+
? ranked
|
|
233
|
+
: ranked.filter((item) => item.score > 0 ||
|
|
234
|
+
implicatedRoots.has(ownershipRoot(item.candidate.path)));
|
|
235
|
+
const planned = [
|
|
236
|
+
...explicit,
|
|
237
|
+
...retrieved.filter((item) => item.candidate.explicitReason === undefined)
|
|
238
|
+
];
|
|
239
|
+
const selected = [];
|
|
240
|
+
let bytes = 0;
|
|
241
|
+
for (const item of planned) {
|
|
242
|
+
if (selected.length >= maximumFiles)
|
|
243
|
+
break;
|
|
244
|
+
if (item.candidate.sizeBytes > EVAL_SOURCE_RETRIEVAL_FILE_BYTES) {
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
if (bytes + item.candidate.sizeBytes > maximumBytes)
|
|
248
|
+
continue;
|
|
249
|
+
const scope = retrievalScope(item.candidate.path);
|
|
250
|
+
selected.push({
|
|
251
|
+
...item.candidate,
|
|
252
|
+
pathScore: item.score +
|
|
253
|
+
(scope === undefined ? 0 : scopeScores.get(scope) ?? 0)
|
|
254
|
+
});
|
|
255
|
+
bytes += item.candidate.sizeBytes;
|
|
256
|
+
}
|
|
257
|
+
return selected.sort((left, right) => canonicalCompare(left.path, right.path));
|
|
258
|
+
}
|
|
259
|
+
const scoreDocuments = (documents, queryTerms) => {
|
|
260
|
+
const prepared = documents.map((document) => ({
|
|
261
|
+
document,
|
|
262
|
+
pathTokens: evaluationSourceTokens(document.path),
|
|
263
|
+
contentTokens: evaluationSourceTokens(document.content)
|
|
264
|
+
}));
|
|
265
|
+
const averagePathLength = prepared.reduce((total, item) => total + item.pathTokens.length, 0) /
|
|
266
|
+
Math.max(1, prepared.length);
|
|
267
|
+
const averageContentLength = prepared.reduce((total, item) => total + item.contentTokens.length, 0) /
|
|
268
|
+
Math.max(1, prepared.length);
|
|
269
|
+
const documentFrequency = new Map(queryTerms.map((term) => [
|
|
270
|
+
term,
|
|
271
|
+
prepared.filter((item) => item.pathTokens.includes(term) ||
|
|
272
|
+
item.contentTokens.includes(term)).length
|
|
273
|
+
]));
|
|
274
|
+
return prepared
|
|
275
|
+
.map(({ document, pathTokens, contentTokens }) => {
|
|
276
|
+
const pathCounts = frequencies(pathTokens);
|
|
277
|
+
const contentCounts = frequencies(contentTokens);
|
|
278
|
+
const pathMatches = queryTerms.filter((term) => (pathCounts.get(term) ?? 0) > 0);
|
|
279
|
+
const contentMatches = queryTerms.filter((term) => (contentCounts.get(term) ?? 0) > 0);
|
|
280
|
+
const score = queryTerms.reduce((total, term) => {
|
|
281
|
+
const frequency = documentFrequency.get(term) ?? 0;
|
|
282
|
+
const inverseDocumentFrequency = Math.log(1 +
|
|
283
|
+
(prepared.length - frequency + 0.5) /
|
|
284
|
+
(frequency + 0.5));
|
|
285
|
+
return (total +
|
|
286
|
+
inverseDocumentFrequency *
|
|
287
|
+
(3 *
|
|
288
|
+
bm25({
|
|
289
|
+
termFrequency: pathCounts.get(term) ?? 0,
|
|
290
|
+
length: pathTokens.length,
|
|
291
|
+
averageLength: averagePathLength
|
|
292
|
+
}) +
|
|
293
|
+
bm25({
|
|
294
|
+
termFrequency: contentCounts.get(term) ?? 0,
|
|
295
|
+
length: contentTokens.length,
|
|
296
|
+
averageLength: averageContentLength
|
|
297
|
+
})));
|
|
298
|
+
}, 0);
|
|
299
|
+
return {
|
|
300
|
+
document,
|
|
301
|
+
score: score +
|
|
302
|
+
(document.explicitReason === undefined ? 0 : 1_000_000),
|
|
303
|
+
pathMatches,
|
|
304
|
+
contentMatches
|
|
305
|
+
};
|
|
306
|
+
})
|
|
307
|
+
.sort((left, right) => right.score - left.score ||
|
|
308
|
+
canonicalCompare(left.document.path, right.document.path));
|
|
309
|
+
};
|
|
310
|
+
export function selectEvaluationSourcePacket(input) {
|
|
311
|
+
const queryTerms = positiveQueryTerms(input);
|
|
312
|
+
const ranked = scoreDocuments(input.documents, queryTerms);
|
|
313
|
+
const hasPositiveMatch = ranked.some((item) => item.pathMatches.length > 0 ||
|
|
314
|
+
item.contentMatches.length > 0);
|
|
315
|
+
const candidates = hasPositiveMatch
|
|
316
|
+
? ranked.filter((item) => item.document.explicitReason !== undefined ||
|
|
317
|
+
item.pathMatches.length > 0 ||
|
|
318
|
+
item.contentMatches.length > 0)
|
|
319
|
+
: ranked;
|
|
320
|
+
const selected = [];
|
|
321
|
+
let bytes = 0;
|
|
322
|
+
for (const [rankIndex, item] of candidates.entries()) {
|
|
323
|
+
if (selected.length >= input.maximumFiles)
|
|
324
|
+
break;
|
|
325
|
+
if (bytes + item.document.sizeBytes > input.maximumBytes)
|
|
326
|
+
continue;
|
|
327
|
+
const terms = [
|
|
328
|
+
...new Set([...item.pathMatches, ...item.contentMatches])
|
|
329
|
+
].sort(canonicalCompare);
|
|
330
|
+
selected.push({
|
|
331
|
+
...item.document,
|
|
332
|
+
inclusionReason: item.document.explicitReason === undefined
|
|
333
|
+
? terms.length === 0
|
|
334
|
+
? "bounded fallback source; no positive query term matched"
|
|
335
|
+
: [
|
|
336
|
+
`sparse retrieval rank ${String(rankIndex + 1)} in ${ownershipRoot(item.document.path)}`,
|
|
337
|
+
`matched positive terms: ${terms.join(", ")}`,
|
|
338
|
+
`fields: ${item.pathMatches.length > 0 &&
|
|
339
|
+
item.contentMatches.length > 0
|
|
340
|
+
? "path+content"
|
|
341
|
+
: item.pathMatches.length > 0
|
|
342
|
+
? "path"
|
|
343
|
+
: "content"}`
|
|
344
|
+
].join("; ")
|
|
345
|
+
: `explicit inclusion: ${item.document.explicitReason}`
|
|
346
|
+
});
|
|
347
|
+
bytes += item.document.sizeBytes;
|
|
348
|
+
}
|
|
349
|
+
return selected.sort((left, right) => canonicalCompare(left.path, right.path));
|
|
350
|
+
}
|
|
351
|
+
const rankEvidenceBlocks = (documents, queryTerms) => {
|
|
352
|
+
const prepared = documents.flatMap((document) => {
|
|
353
|
+
const pathTokens = evaluationSourceTokens(document.path);
|
|
354
|
+
return document.evidenceSource.blocks.map((block) => ({
|
|
355
|
+
document,
|
|
356
|
+
block,
|
|
357
|
+
pathTokens,
|
|
358
|
+
contentTokens: evaluationSourceTokens(block.text)
|
|
359
|
+
}));
|
|
360
|
+
});
|
|
361
|
+
const averagePathLength = prepared.reduce((total, item) => total + item.pathTokens.length, 0) /
|
|
362
|
+
Math.max(1, prepared.length);
|
|
363
|
+
const averageContentLength = prepared.reduce((total, item) => total + item.contentTokens.length, 0) /
|
|
364
|
+
Math.max(1, prepared.length);
|
|
365
|
+
const documentFrequency = new Map(queryTerms.map((term) => [
|
|
366
|
+
term,
|
|
367
|
+
prepared.filter((item) => item.pathTokens.includes(term) ||
|
|
368
|
+
item.contentTokens.includes(term)).length
|
|
369
|
+
]));
|
|
370
|
+
return prepared
|
|
371
|
+
.map(({ document, block, pathTokens, contentTokens }) => {
|
|
372
|
+
const pathCounts = frequencies(pathTokens);
|
|
373
|
+
const contentCounts = frequencies(contentTokens);
|
|
374
|
+
const pathMatches = queryTerms.filter((term) => (pathCounts.get(term) ?? 0) > 0);
|
|
375
|
+
const contentMatches = queryTerms.filter((term) => (contentCounts.get(term) ?? 0) > 0);
|
|
376
|
+
const score = queryTerms.reduce((total, term) => {
|
|
377
|
+
const frequency = documentFrequency.get(term) ?? 0;
|
|
378
|
+
const inverseDocumentFrequency = Math.log(1 +
|
|
379
|
+
(prepared.length - frequency + 0.5) /
|
|
380
|
+
(frequency + 0.5));
|
|
381
|
+
return (total +
|
|
382
|
+
inverseDocumentFrequency *
|
|
383
|
+
(3 *
|
|
384
|
+
bm25({
|
|
385
|
+
termFrequency: pathCounts.get(term) ?? 0,
|
|
386
|
+
length: pathTokens.length,
|
|
387
|
+
averageLength: averagePathLength
|
|
388
|
+
}) +
|
|
389
|
+
bm25({
|
|
390
|
+
termFrequency: contentCounts.get(term) ?? 0,
|
|
391
|
+
length: contentTokens.length,
|
|
392
|
+
averageLength: averageContentLength
|
|
393
|
+
})));
|
|
394
|
+
}, 0);
|
|
395
|
+
return {
|
|
396
|
+
document,
|
|
397
|
+
block,
|
|
398
|
+
score: score +
|
|
399
|
+
(document.pathScore ?? 0) +
|
|
400
|
+
(document.explicitReason === undefined ? 0 : 1_000_000),
|
|
401
|
+
matchedTermCount: new Set([
|
|
402
|
+
...pathMatches,
|
|
403
|
+
...contentMatches
|
|
404
|
+
]).size,
|
|
405
|
+
pathMatches,
|
|
406
|
+
contentMatches
|
|
407
|
+
};
|
|
408
|
+
})
|
|
409
|
+
.sort((left, right) => Number(right.document.explicitReason !== undefined) -
|
|
410
|
+
Number(left.document.explicitReason !== undefined) ||
|
|
411
|
+
right.score - left.score ||
|
|
412
|
+
right.matchedTermCount - left.matchedTermCount ||
|
|
413
|
+
canonicalCompare(left.document.path, right.document.path) ||
|
|
414
|
+
left.block.ordinal - right.block.ordinal);
|
|
415
|
+
};
|
|
416
|
+
/**
|
|
417
|
+
* Selects compiler-owned evidence blocks rather than whole files. Packet
|
|
418
|
+
* assembly proceeds in per-source rounds so one large source cannot consume
|
|
419
|
+
* the complete authoring budget before complementary owners can compete.
|
|
420
|
+
*/
|
|
421
|
+
export function selectEvaluationEvidencePacket(input) {
|
|
422
|
+
const maximumBlocks = input.maximumBlocks ?? EVAL_SOURCE_RETRIEVAL_PACKET_BLOCKS;
|
|
423
|
+
const maximumBlocksPerSource = input.maximumBlocksPerSource ??
|
|
424
|
+
EVAL_SOURCE_RETRIEVAL_BLOCKS_PER_SOURCE;
|
|
425
|
+
const facets = positiveQueryFacets(input.targetDimensions).map((facet) => {
|
|
426
|
+
const ranked = rankEvidenceBlocks(input.documents, facet.terms);
|
|
427
|
+
const positive = ranked.filter((item) => item.document.explicitReason !== undefined ||
|
|
428
|
+
item.pathMatches.length > 0 ||
|
|
429
|
+
item.contentMatches.length > 0);
|
|
430
|
+
return {
|
|
431
|
+
...facet,
|
|
432
|
+
candidates: positive.length > 0 ? positive : ranked
|
|
433
|
+
};
|
|
434
|
+
});
|
|
435
|
+
const selected = [];
|
|
436
|
+
const selectedIds = new Set();
|
|
437
|
+
let selectedBytes = 0;
|
|
438
|
+
const admit = (facet, predicate) => {
|
|
439
|
+
const item = facet.candidates.find((candidate) => {
|
|
440
|
+
if (selectedIds.has(candidate.block.id) || !predicate(candidate)) {
|
|
441
|
+
return false;
|
|
442
|
+
}
|
|
443
|
+
const sourceCount = selected.filter((selectedItem) => selectedItem.document.path === candidate.document.path).length;
|
|
444
|
+
if (sourceCount >= maximumBlocksPerSource)
|
|
445
|
+
return false;
|
|
446
|
+
const blockBytes = Buffer.byteLength(candidate.block.text, "utf8");
|
|
447
|
+
return selectedBytes + blockBytes <= input.maximumBytes;
|
|
448
|
+
});
|
|
449
|
+
if (item === undefined)
|
|
450
|
+
return false;
|
|
451
|
+
selected.push({ ...item, facetLabel: facet.label });
|
|
452
|
+
selectedIds.add(item.block.id);
|
|
453
|
+
selectedBytes += Buffer.byteLength(item.block.text, "utf8");
|
|
454
|
+
return true;
|
|
455
|
+
};
|
|
456
|
+
for (const facet of facets) {
|
|
457
|
+
if (selected.length >= maximumBlocks)
|
|
458
|
+
break;
|
|
459
|
+
admit(facet, (candidate) => (candidate.document.sourceClass === "implementation" ||
|
|
460
|
+
candidate.document.sourceClass === "protocol") &&
|
|
461
|
+
!selected.some((selectedItem) => selectedItem.document.path === candidate.document.path));
|
|
462
|
+
}
|
|
463
|
+
while (selected.length < maximumBlocks) {
|
|
464
|
+
let admitted = false;
|
|
465
|
+
for (const facet of facets) {
|
|
466
|
+
if (selected.length >= maximumBlocks)
|
|
467
|
+
break;
|
|
468
|
+
admitted = admit(facet, () => true) || admitted;
|
|
469
|
+
}
|
|
470
|
+
if (!admitted)
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
const grouped = new Map();
|
|
474
|
+
for (const item of selected) {
|
|
475
|
+
const values = grouped.get(item.document.path) ?? [];
|
|
476
|
+
values.push(item);
|
|
477
|
+
grouped.set(item.document.path, values);
|
|
478
|
+
}
|
|
479
|
+
return [...grouped.entries()]
|
|
480
|
+
.map(([path, items]) => {
|
|
481
|
+
const first = items[0];
|
|
482
|
+
const blocks = items
|
|
483
|
+
.map((item) => item.block)
|
|
484
|
+
.sort((left, right) => left.ordinal - right.ordinal);
|
|
485
|
+
const terms = [
|
|
486
|
+
...new Set(items.flatMap((item) => [
|
|
487
|
+
...item.pathMatches,
|
|
488
|
+
...item.contentMatches
|
|
489
|
+
]))
|
|
490
|
+
].sort(canonicalCompare);
|
|
491
|
+
const facets = [
|
|
492
|
+
...new Set(items.map((item) => item.facetLabel))
|
|
493
|
+
].sort(canonicalCompare);
|
|
494
|
+
return {
|
|
495
|
+
source: {
|
|
496
|
+
path,
|
|
497
|
+
sizeBytes: first.document.sizeBytes,
|
|
498
|
+
sourceClass: first.document.sourceClass,
|
|
499
|
+
...(first.document.explicitReason === undefined
|
|
500
|
+
? {}
|
|
501
|
+
: { explicitReason: first.document.explicitReason })
|
|
502
|
+
},
|
|
503
|
+
blocks,
|
|
504
|
+
sizeBytes: blocks.reduce((total, block) => total + Buffer.byteLength(block.text, "utf8"), 0),
|
|
505
|
+
inclusionReason: first.document.explicitReason === undefined
|
|
506
|
+
? terms.length === 0
|
|
507
|
+
? `bounded block fallback in ${ownershipRoot(path)}`
|
|
508
|
+
: `compiler-block retrieval in ${ownershipRoot(path)}; facets: ${facets.join(", ")}; matched positive terms: ${terms.join(", ")}`
|
|
509
|
+
: `explicit inclusion: ${first.document.explicitReason}`
|
|
510
|
+
};
|
|
511
|
+
})
|
|
512
|
+
.sort((left, right) => canonicalCompare(left.source.path, right.source.path));
|
|
513
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { EvalCriterion, EvalDimensionCase, EvalEvaluationProposal, EvalNegativeControl, EvalPositiveControl } from "./project-contracts.js";
|
|
2
|
+
export declare const EVAL_STRUCTURE_POLICY_VERSION: 1;
|
|
3
|
+
export type EvalCandidateCaseProjection = {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly prompt: string;
|
|
6
|
+
readonly context: string;
|
|
7
|
+
};
|
|
8
|
+
export type EvalHiddenOracleProjection = {
|
|
9
|
+
readonly id: string;
|
|
10
|
+
readonly rubric: string;
|
|
11
|
+
readonly criteria: readonly EvalCriterion[];
|
|
12
|
+
readonly positiveControls: readonly EvalPositiveControl[];
|
|
13
|
+
readonly negativeControls: readonly EvalNegativeControl[];
|
|
14
|
+
};
|
|
15
|
+
export type EvalStructureReport = {
|
|
16
|
+
readonly policyVersion: typeof EVAL_STRUCTURE_POLICY_VERSION;
|
|
17
|
+
readonly evidenceSourceCount: number;
|
|
18
|
+
readonly evidenceBlockCount: number;
|
|
19
|
+
readonly caseCount: number;
|
|
20
|
+
readonly duplicateEvidenceSelectionGroups: readonly (readonly string[])[];
|
|
21
|
+
};
|
|
22
|
+
export declare const renderEvaluationCriteria: (criteria: readonly EvalCriterion[]) => string;
|
|
23
|
+
export declare function candidateCaseProjection(testCase: EvalDimensionCase): EvalCandidateCaseProjection;
|
|
24
|
+
export declare function hiddenOracleProjection(testCase: EvalDimensionCase): EvalHiddenOracleProjection;
|
|
25
|
+
export declare function assertEvaluationStructure(input: {
|
|
26
|
+
readonly proposal: EvalEvaluationProposal;
|
|
27
|
+
readonly sourceInventory: readonly string[];
|
|
28
|
+
}): EvalStructureReport;
|
|
29
|
+
export declare function evaluationStructureReportDigest(report: EvalStructureReport): string;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { assertEvaluationEvidenceSources, renderEvaluationEvidenceContext, resolveEvaluationEvidence } from "./evaluation-evidence.js";
|
|
3
|
+
import { EVAL_AUTHORING_CASE_EVIDENCE_BYTES, EVAL_AUTHORING_EVIDENCE_BLOCK_BYTES } from "./evaluation-authoring-policy.js";
|
|
4
|
+
export const EVAL_STRUCTURE_POLICY_VERSION = 1;
|
|
5
|
+
const sha256 = (value) => createHash("sha256").update(value).digest("hex");
|
|
6
|
+
const uniqueIds = (values, label) => {
|
|
7
|
+
if (new Set(values.map((value) => value.id)).size !== values.length) {
|
|
8
|
+
throw new Error(`${label} ids must be unique`);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
export const renderEvaluationCriteria = (criteria) => criteria
|
|
12
|
+
.map((criterion) => `${criterion.importance === "critical" ? "Critical" : "Supporting"} criterion ${criterion.id}: ${criterion.description}`)
|
|
13
|
+
.join("\n");
|
|
14
|
+
const compiledCaseFields = (testCase) => {
|
|
15
|
+
if (testCase.context === undefined ||
|
|
16
|
+
testCase.evidenceIds === undefined ||
|
|
17
|
+
testCase.criteria === undefined ||
|
|
18
|
+
testCase.positiveControls === undefined ||
|
|
19
|
+
testCase.negativeControls === undefined) {
|
|
20
|
+
throw new Error(`evaluation case ${JSON.stringify(testCase.id)} is not compiler-backed`);
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
context: testCase.context,
|
|
24
|
+
evidenceIds: testCase.evidenceIds,
|
|
25
|
+
criteria: testCase.criteria,
|
|
26
|
+
positiveControls: testCase.positiveControls,
|
|
27
|
+
negativeControls: testCase.negativeControls
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
const assertControls = (caseId, criteria, positiveControls, negativeControls) => {
|
|
31
|
+
if (criteria.length === 0 || !criteria.some((criterion) => criterion.importance === "critical")) {
|
|
32
|
+
throw new Error(`evaluation case ${JSON.stringify(caseId)} requires a critical criterion`);
|
|
33
|
+
}
|
|
34
|
+
uniqueIds(criteria, `evaluation case ${JSON.stringify(caseId)} criterion`);
|
|
35
|
+
if (positiveControls.length === 0) {
|
|
36
|
+
throw new Error(`evaluation case ${JSON.stringify(caseId)} requires a positive control`);
|
|
37
|
+
}
|
|
38
|
+
uniqueIds(positiveControls, `evaluation case ${JSON.stringify(caseId)} positive control`);
|
|
39
|
+
uniqueIds(negativeControls, `evaluation case ${JSON.stringify(caseId)} negative control`);
|
|
40
|
+
const criterionIds = new Set(criteria.map((criterion) => criterion.id));
|
|
41
|
+
for (const negative of negativeControls) {
|
|
42
|
+
if (negative.targetedCriterionIds.length === 0 ||
|
|
43
|
+
new Set(negative.targetedCriterionIds).size !==
|
|
44
|
+
negative.targetedCriterionIds.length ||
|
|
45
|
+
negative.targetedCriterionIds.some((criterionId) => !criterionIds.has(criterionId))) {
|
|
46
|
+
throw new Error(`evaluation case ${JSON.stringify(caseId)} has an invalid negative-control target`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
for (const kind of [
|
|
50
|
+
"missing-criterion",
|
|
51
|
+
"forbidden-behavior",
|
|
52
|
+
"non-responsive"
|
|
53
|
+
]) {
|
|
54
|
+
if (!negativeControls.some((control) => control.kind === kind)) {
|
|
55
|
+
throw new Error(`evaluation case ${JSON.stringify(caseId)} requires a ${kind} negative control`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
export function candidateCaseProjection(testCase) {
|
|
60
|
+
const fields = compiledCaseFields(testCase);
|
|
61
|
+
return {
|
|
62
|
+
id: testCase.id,
|
|
63
|
+
prompt: testCase.prompt,
|
|
64
|
+
context: fields.context
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export function hiddenOracleProjection(testCase) {
|
|
68
|
+
const fields = compiledCaseFields(testCase);
|
|
69
|
+
return {
|
|
70
|
+
id: testCase.id,
|
|
71
|
+
rubric: testCase.rubric,
|
|
72
|
+
criteria: fields.criteria,
|
|
73
|
+
positiveControls: fields.positiveControls,
|
|
74
|
+
negativeControls: fields.negativeControls
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export function assertEvaluationStructure(input) {
|
|
78
|
+
const { proposal } = input;
|
|
79
|
+
const evidenceSources = proposal.evidenceSources;
|
|
80
|
+
if (evidenceSources === undefined || evidenceSources.length === 0) {
|
|
81
|
+
throw new Error("evaluation proposal has no compiler-owned evidence sources");
|
|
82
|
+
}
|
|
83
|
+
assertEvaluationEvidenceSources(evidenceSources);
|
|
84
|
+
const inventory = new Set(input.sourceInventory);
|
|
85
|
+
for (const source of evidenceSources) {
|
|
86
|
+
if (!inventory.has(source.path)) {
|
|
87
|
+
throw new Error(`evaluation evidence source is outside the project inventory: ${JSON.stringify(source.path)}`);
|
|
88
|
+
}
|
|
89
|
+
for (const block of source.blocks) {
|
|
90
|
+
if (Buffer.byteLength(block.text, "utf8") > EVAL_AUTHORING_EVIDENCE_BLOCK_BYTES) {
|
|
91
|
+
throw new Error(`evaluation evidence block exceeds policy bytes: ${JSON.stringify(block.id)}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const cases = [
|
|
96
|
+
...proposal.suites.flatMap((suite) => suite.cases.map((testCase) => ({
|
|
97
|
+
identity: `${suite.dimensionId}/${testCase.id}`,
|
|
98
|
+
testCase
|
|
99
|
+
}))),
|
|
100
|
+
...proposal.compositionSuite.cases.map((testCase) => ({
|
|
101
|
+
identity: `composition/${testCase.id}`,
|
|
102
|
+
testCase
|
|
103
|
+
}))
|
|
104
|
+
];
|
|
105
|
+
const selectionCases = new Map();
|
|
106
|
+
for (const { identity, testCase } of cases) {
|
|
107
|
+
const fields = compiledCaseFields(testCase);
|
|
108
|
+
const selected = resolveEvaluationEvidence({
|
|
109
|
+
sources: evidenceSources,
|
|
110
|
+
evidenceIds: fields.evidenceIds,
|
|
111
|
+
maximumContextBytes: EVAL_AUTHORING_CASE_EVIDENCE_BYTES
|
|
112
|
+
});
|
|
113
|
+
if (fields.context !== renderEvaluationEvidenceContext(selected)) {
|
|
114
|
+
throw new Error(`evaluation case ${JSON.stringify(testCase.id)} context is not compiler-rendered`);
|
|
115
|
+
}
|
|
116
|
+
assertControls(testCase.id, fields.criteria, fields.positiveControls, fields.negativeControls);
|
|
117
|
+
if (testCase.rubric !== renderEvaluationCriteria(fields.criteria)) {
|
|
118
|
+
throw new Error(`evaluation case ${JSON.stringify(testCase.id)} rubric is not compiler-rendered`);
|
|
119
|
+
}
|
|
120
|
+
const fingerprint = fields.evidenceIds.join("\u0000");
|
|
121
|
+
const matching = selectionCases.get(fingerprint) ?? [];
|
|
122
|
+
matching.push(identity);
|
|
123
|
+
selectionCases.set(fingerprint, matching);
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
policyVersion: EVAL_STRUCTURE_POLICY_VERSION,
|
|
127
|
+
evidenceSourceCount: evidenceSources.length,
|
|
128
|
+
evidenceBlockCount: evidenceSources.reduce((count, source) => count + source.blocks.length, 0),
|
|
129
|
+
caseCount: cases.length,
|
|
130
|
+
duplicateEvidenceSelectionGroups: [...selectionCases.values()]
|
|
131
|
+
.filter((caseIds) => caseIds.length > 1)
|
|
132
|
+
.map((caseIds) => [...caseIds].sort((left, right) => left < right ? -1 : left > right ? 1 : 0))
|
|
133
|
+
.sort((left, right) => left[0] < right[0] ? -1 : left[0] > right[0] ? 1 : 0)
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
export function evaluationStructureReportDigest(report) {
|
|
137
|
+
return sha256(JSON.stringify(report));
|
|
138
|
+
}
|