@velum-labs/routekit-eval-setup 1.0.26 → 1.1.1

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.
Files changed (38) hide show
  1. package/dist/adapters/git-basis-snapshot.d.ts +27 -0
  2. package/dist/adapters/git-basis-snapshot.js +178 -0
  3. package/dist/basis-candidates.d.ts +72 -0
  4. package/dist/basis-candidates.js +157 -0
  5. package/dist/basis-projection.d.ts +9 -0
  6. package/dist/basis-projection.js +30 -0
  7. package/dist/basis-validation.d.ts +38 -0
  8. package/dist/basis-validation.js +187 -0
  9. package/dist/effect-api.d.ts +8 -0
  10. package/dist/effect-api.js +5 -0
  11. package/dist/errors.d.ts +11 -1
  12. package/dist/errors.js +5 -0
  13. package/dist/index.d.ts +15 -3
  14. package/dist/index.js +10 -2
  15. package/dist/project-artifacts.d.ts +26 -1
  16. package/dist/project-artifacts.js +52 -1
  17. package/dist/project-contracts.d.ts +3594 -0
  18. package/dist/project-contracts.js +344 -1
  19. package/dist/project-store.d.ts +3 -1
  20. package/dist/project-store.js +39 -33
  21. package/dist/project-workflow.d.ts +2 -2
  22. package/dist/services/basis-authoring/service.d.ts +253 -0
  23. package/dist/services/basis-authoring/service.js +547 -0
  24. package/dist/services/basis-onboarding/service.d.ts +48 -0
  25. package/dist/services/basis-onboarding/service.js +491 -0
  26. package/dist/services/basis-repair/service.d.ts +25 -0
  27. package/dist/services/basis-repair/service.js +249 -0
  28. package/dist/test/basis-authoring.test.d.ts +1 -0
  29. package/dist/test/basis-authoring.test.js +194 -0
  30. package/dist/test/basis-onboarding.test.d.ts +1 -0
  31. package/dist/test/basis-onboarding.test.js +385 -0
  32. package/dist/test/basis-repair.test.d.ts +1 -0
  33. package/dist/test/basis-repair.test.js +338 -0
  34. package/dist/test/basis-v3.test.d.ts +1 -0
  35. package/dist/test/basis-v3.test.js +262 -0
  36. package/dist/test/project-v2.test.d.ts +1 -0
  37. package/dist/test/project-v2.test.js +99 -0
  38. package/package.json +4 -3
@@ -0,0 +1,27 @@
1
+ import { Effect } from "effect";
2
+ import { EvalBasisSnapshotError } from "../errors.js";
3
+ import type { FrozenRepositorySnapshotV3 } from "../project-contracts.js";
4
+ export type CapturedRepositorySnapshotV3 = {
5
+ readonly snapshot: FrozenRepositorySnapshotV3;
6
+ readonly sourceInventory: readonly string[];
7
+ };
8
+ export type FrozenRepositorySourceV3 = {
9
+ readonly path: string;
10
+ readonly content: string;
11
+ };
12
+ /**
13
+ * Reads a deterministic bounded source sample from the exact frozen Git tree.
14
+ * Mutable worktree contents are never consulted.
15
+ */
16
+ export declare function readFrozenRepositorySourcesV3(input: {
17
+ readonly repositoryRoot: string;
18
+ readonly tree: string;
19
+ readonly sourceInventory: readonly string[];
20
+ }): Effect.Effect<readonly FrozenRepositorySourceV3[], EvalBasisSnapshotError>;
21
+ /** Git adapter for an exact, bounded repository snapshot. */
22
+ export declare function captureFrozenRepositorySnapshotV3(input: {
23
+ readonly repositoryRoot: string;
24
+ readonly requestedRef: string;
25
+ readonly allowDirty: boolean;
26
+ readonly capturedAt: string;
27
+ }): Effect.Effect<CapturedRepositorySnapshotV3, EvalBasisSnapshotError>;
@@ -0,0 +1,178 @@
1
+ import { execFile } from "node:child_process";
2
+ import { lstat, readFile, realpath } from "node:fs/promises";
3
+ import { relative, resolve, sep } from "node:path";
4
+ import { promisify } from "node:util";
5
+ import { routingContractDigest } from "@velum-labs/routekit-eval-contracts";
6
+ import { Effect } from "effect";
7
+ import { EvalBasisSnapshotError } from "../errors.js";
8
+ const execFilePromise = promisify(execFile);
9
+ const MAX_TREE_PATHS = 40_000;
10
+ const MAX_DIRTY_BYTES = 8 * 1024 * 1024;
11
+ const MAX_AUTHORING_FILES = 64;
12
+ const MAX_AUTHORING_BYTES = 60_000;
13
+ const failure = (operation, detail, cause) => new EvalBasisSnapshotError({
14
+ operation,
15
+ detail,
16
+ ...(cause === undefined ? {} : { cause })
17
+ });
18
+ function git(root, args, operation) {
19
+ return Effect.tryPromise({
20
+ try: async () => {
21
+ const result = (await execFilePromise("git", ["-C", root, ...args], {
22
+ encoding: "utf8",
23
+ maxBuffer: 16 * 1024 * 1024,
24
+ windowsHide: true
25
+ }));
26
+ return result.stdout;
27
+ },
28
+ catch: (cause) => failure(operation, `git ${args.join(" ")} failed`, cause)
29
+ });
30
+ }
31
+ function pathWithin(root, candidate) {
32
+ const path = relative(root, candidate);
33
+ return (path === "" ||
34
+ (path !== ".." &&
35
+ !path.startsWith(`..${sep}`) &&
36
+ !path.startsWith("/")));
37
+ }
38
+ function dirtyContentDigest(root, status) {
39
+ return Effect.gen(function* () {
40
+ const patch = yield* git(root, ["diff", "--binary", "--no-ext-diff", "HEAD", "--"], "read-dirty-content");
41
+ const untracked = (yield* git(root, ["ls-files", "--others", "--exclude-standard", "-z"], "read-dirty-content"))
42
+ .split("\0")
43
+ .filter((entry) => entry.length > 0)
44
+ .sort();
45
+ let totalBytes = Buffer.byteLength(status, "utf8") + Buffer.byteLength(patch, "utf8");
46
+ const untrackedDigests = [];
47
+ for (const path of untracked) {
48
+ const absolute = resolve(root, path);
49
+ if (!pathWithin(root, absolute)) {
50
+ return yield* failure("read-dirty-content", `untracked path escapes the repository: ${JSON.stringify(path)}`);
51
+ }
52
+ const info = yield* Effect.tryPromise({
53
+ try: () => lstat(absolute),
54
+ catch: (cause) => failure("read-dirty-content", `failed to inspect untracked path ${JSON.stringify(path)}`, cause)
55
+ });
56
+ if (!info.isFile() || info.isSymbolicLink()) {
57
+ return yield* failure("read-dirty-content", `untracked path is not a regular non-symlink file: ${JSON.stringify(path)}`);
58
+ }
59
+ totalBytes += Number(info.size);
60
+ if (totalBytes > MAX_DIRTY_BYTES) {
61
+ return yield* failure("read-dirty-content", `dirty repository evidence exceeds ${String(MAX_DIRTY_BYTES)} bytes`);
62
+ }
63
+ const content = yield* Effect.tryPromise({
64
+ try: () => readFile(absolute),
65
+ catch: (cause) => failure("read-dirty-content", `failed to read untracked path ${JSON.stringify(path)}`, cause)
66
+ });
67
+ untrackedDigests.push({
68
+ path,
69
+ contentDigest: routingContractDigest("routekit.dirty-untracked-content.v1", "content", content.toString("base64"))
70
+ });
71
+ }
72
+ return routingContractDigest("routekit.dirty-repository-patch.v1", "dirty", { status, patch, untracked: untrackedDigests });
73
+ });
74
+ }
75
+ /**
76
+ * Reads a deterministic bounded source sample from the exact frozen Git tree.
77
+ * Mutable worktree contents are never consulted.
78
+ */
79
+ export function readFrozenRepositorySourcesV3(input) {
80
+ return Effect.gen(function* () {
81
+ const root = yield* Effect.tryPromise({
82
+ try: () => realpath(input.repositoryRoot),
83
+ catch: (cause) => failure("resolve-root", `failed to resolve ${JSON.stringify(input.repositoryRoot)}`, cause)
84
+ });
85
+ const selected = input.sourceInventory
86
+ .filter((path) => /(^|\/)(readme(?:\.[^/]*)?|package\.json|[^/]+\.(?:ts|tsx|js|jsx|md|json))$/iu.test(path))
87
+ .sort((left, right) => {
88
+ const rank = (path) => /(^|\/)readme(?:\.[^/]*)?$/iu.test(path)
89
+ ? 0
90
+ : /(^|\/)package\.json$/u.test(path)
91
+ ? 1
92
+ : path.endsWith(".md")
93
+ ? 2
94
+ : 3;
95
+ return rank(left) - rank(right) || left.localeCompare(right);
96
+ });
97
+ const sources = [];
98
+ let totalBytes = 0;
99
+ for (const path of selected) {
100
+ if (sources.length >= MAX_AUTHORING_FILES)
101
+ break;
102
+ if (path.trim().length === 0 ||
103
+ path.startsWith("/") ||
104
+ path.split("/").includes("..") ||
105
+ path.includes("\0")) {
106
+ return yield* failure("read-tree", `source inventory contains an unsafe path: ${JSON.stringify(path)}`);
107
+ }
108
+ const content = yield* git(root, ["show", `${input.tree}:${path}`], "read-tree");
109
+ const bytes = Buffer.byteLength(content, "utf8");
110
+ if (bytes > MAX_AUTHORING_BYTES - totalBytes)
111
+ continue;
112
+ sources.push({ path, content });
113
+ totalBytes += bytes;
114
+ }
115
+ if (sources.length === 0) {
116
+ return yield* failure("read-tree", "frozen repository tree contains no bounded authoring source");
117
+ }
118
+ return sources;
119
+ });
120
+ }
121
+ /** Git adapter for an exact, bounded repository snapshot. */
122
+ export function captureFrozenRepositorySnapshotV3(input) {
123
+ return Effect.gen(function* () {
124
+ const root = yield* Effect.tryPromise({
125
+ try: () => realpath(input.repositoryRoot),
126
+ catch: (cause) => failure("resolve-root", `failed to resolve ${JSON.stringify(input.repositoryRoot)}`, cause)
127
+ });
128
+ const status = yield* git(root, ["status", "--porcelain=v1", "--untracked-files=normal"], "inspect-status");
129
+ const dirty = status.trim().length > 0;
130
+ if (dirty && !input.allowDirty) {
131
+ return yield* failure("inspect-status", "repository is dirty; commit or stash changes before Classification V3 onboarding");
132
+ }
133
+ const requestedRef = input.requestedRef.trim();
134
+ if (requestedRef.length === 0) {
135
+ return yield* failure("resolve-ref", "snapshot ref must not be empty");
136
+ }
137
+ const commit = (yield* git(root, ["rev-parse", "--verify", `${requestedRef}^{commit}`], "resolve-ref")).trim();
138
+ const tree = (yield* git(root, ["rev-parse", "--verify", `${requestedRef}^{tree}`], "resolve-ref")).trim();
139
+ const sourceInventory = (yield* git(root, ["ls-tree", "-r", "--name-only", "-z", tree], "read-tree"))
140
+ .split("\0")
141
+ .filter((entry) => entry.length > 0);
142
+ if (sourceInventory.length > MAX_TREE_PATHS) {
143
+ return yield* failure("read-tree", `repository tree exceeds ${String(MAX_TREE_PATHS)} paths`);
144
+ }
145
+ const sourceInventoryDigest = routingContractDigest("routekit.repository-source-inventory.v1", "paths", sourceInventory);
146
+ const repositoryRootDigest = routingContractDigest("routekit.repository-root.v1", "root", root);
147
+ const dirtyPatchDigest = dirty
148
+ ? yield* dirtyContentDigest(root, status)
149
+ : undefined;
150
+ const repositoryDigest = routingContractDigest("routekit.frozen-repository-snapshot.v1", "snapshot", {
151
+ repositoryRootDigest,
152
+ requestedRef,
153
+ commit,
154
+ tree,
155
+ dirty,
156
+ ...(dirtyPatchDigest === undefined
157
+ ? {}
158
+ : { dirtyPatchDigest }),
159
+ sourceInventoryDigest
160
+ });
161
+ return {
162
+ snapshot: {
163
+ repositoryRootDigest,
164
+ requestedRef,
165
+ commit,
166
+ tree,
167
+ repositoryDigest,
168
+ capturedAt: input.capturedAt,
169
+ dirty,
170
+ ...(dirtyPatchDigest === undefined
171
+ ? {}
172
+ : { dirtyPatchDigest }),
173
+ sourceInventoryDigest
174
+ },
175
+ sourceInventory
176
+ };
177
+ });
178
+ }
@@ -0,0 +1,72 @@
1
+ import type { BasisCandidateRecipeV3, BasisTaskRecordV3, BasisTaskSplitV3 } from "./project-contracts.js";
2
+ export declare const BASIS_AUTHOR_INPUT_TOKENS_PER_ATTEMPT = 65536;
3
+ export declare const BASIS_AUTHOR_OUTPUT_TOKENS_PER_ATTEMPT = 16384;
4
+ export declare const DEFAULT_BASIS_CANDIDATE_RECIPES_V3: readonly [{
5
+ readonly id: "incumbent-enriched-8";
6
+ readonly dimensionCount: 8;
7
+ readonly historySize: 0;
8
+ readonly sampling: "none";
9
+ readonly includeChangedPathStatistics: false;
10
+ readonly deterministic: true;
11
+ }, {
12
+ readonly id: "structure-only-8";
13
+ readonly dimensionCount: 8;
14
+ readonly historySize: 0;
15
+ readonly sampling: "none";
16
+ readonly includeChangedPathStatistics: false;
17
+ readonly deterministic: false;
18
+ }, {
19
+ readonly id: "hybrid-paths-20-diverse-8";
20
+ readonly dimensionCount: 8;
21
+ readonly historySize: 20;
22
+ readonly sampling: "diverse";
23
+ readonly includeChangedPathStatistics: true;
24
+ readonly deterministic: false;
25
+ }, {
26
+ readonly id: "hybrid-paths-40-diverse-6";
27
+ readonly dimensionCount: 6;
28
+ readonly historySize: 40;
29
+ readonly sampling: "diverse";
30
+ readonly includeChangedPathStatistics: true;
31
+ readonly deterministic: false;
32
+ }, {
33
+ readonly id: "hybrid-paths-40-diverse-8";
34
+ readonly dimensionCount: 8;
35
+ readonly historySize: 40;
36
+ readonly sampling: "diverse";
37
+ readonly includeChangedPathStatistics: true;
38
+ readonly deterministic: false;
39
+ }, {
40
+ readonly id: "hybrid-paths-40-diverse-10";
41
+ readonly dimensionCount: 10;
42
+ readonly historySize: 40;
43
+ readonly sampling: "diverse";
44
+ readonly includeChangedPathStatistics: true;
45
+ readonly deterministic: false;
46
+ }, {
47
+ readonly id: "hybrid-paths-40-recent-8";
48
+ readonly dimensionCount: 8;
49
+ readonly historySize: 40;
50
+ readonly sampling: "recent";
51
+ readonly includeChangedPathStatistics: true;
52
+ readonly deterministic: false;
53
+ }, {
54
+ readonly id: "hybrid-paths-80-diverse-8";
55
+ readonly dimensionCount: 8;
56
+ readonly historySize: 80;
57
+ readonly sampling: "diverse";
58
+ readonly includeChangedPathStatistics: true;
59
+ readonly deterministic: false;
60
+ }];
61
+ /**
62
+ * Freezes oldest→newest construction/validation/final cohorts.
63
+ *
64
+ * The default keeps 12 validation and 28 final tasks whenever at least one
65
+ * older construction task remains. Sparse histories fail closed with explicit
66
+ * provisional/no-final warnings rather than borrowing from held-out cohorts.
67
+ */
68
+ export declare function splitBasisTasksChronologicallyV3(tasks: readonly BasisTaskRecordV3[], input?: {
69
+ readonly validationCount?: number;
70
+ readonly finalCount?: number;
71
+ }): BasisTaskSplitV3;
72
+ export declare function selectConstructionTasksForRecipeV3(split: BasisTaskSplitV3, recipe: BasisCandidateRecipeV3): readonly BasisTaskRecordV3[];
@@ -0,0 +1,157 @@
1
+ import { routingContractDigest } from "@velum-labs/routekit-eval-contracts";
2
+ export const BASIS_AUTHOR_INPUT_TOKENS_PER_ATTEMPT = 65_536;
3
+ export const BASIS_AUTHOR_OUTPUT_TOKENS_PER_ATTEMPT = 16_384;
4
+ export const DEFAULT_BASIS_CANDIDATE_RECIPES_V3 = [
5
+ {
6
+ id: "incumbent-enriched-8",
7
+ dimensionCount: 8,
8
+ historySize: 0,
9
+ sampling: "none",
10
+ includeChangedPathStatistics: false,
11
+ deterministic: true
12
+ },
13
+ {
14
+ id: "structure-only-8",
15
+ dimensionCount: 8,
16
+ historySize: 0,
17
+ sampling: "none",
18
+ includeChangedPathStatistics: false,
19
+ deterministic: false
20
+ },
21
+ {
22
+ id: "hybrid-paths-20-diverse-8",
23
+ dimensionCount: 8,
24
+ historySize: 20,
25
+ sampling: "diverse",
26
+ includeChangedPathStatistics: true,
27
+ deterministic: false
28
+ },
29
+ {
30
+ id: "hybrid-paths-40-diverse-6",
31
+ dimensionCount: 6,
32
+ historySize: 40,
33
+ sampling: "diverse",
34
+ includeChangedPathStatistics: true,
35
+ deterministic: false
36
+ },
37
+ {
38
+ id: "hybrid-paths-40-diverse-8",
39
+ dimensionCount: 8,
40
+ historySize: 40,
41
+ sampling: "diverse",
42
+ includeChangedPathStatistics: true,
43
+ deterministic: false
44
+ },
45
+ {
46
+ id: "hybrid-paths-40-diverse-10",
47
+ dimensionCount: 10,
48
+ historySize: 40,
49
+ sampling: "diverse",
50
+ includeChangedPathStatistics: true,
51
+ deterministic: false
52
+ },
53
+ {
54
+ id: "hybrid-paths-40-recent-8",
55
+ dimensionCount: 8,
56
+ historySize: 40,
57
+ sampling: "recent",
58
+ includeChangedPathStatistics: true,
59
+ deterministic: false
60
+ },
61
+ {
62
+ id: "hybrid-paths-80-diverse-8",
63
+ dimensionCount: 8,
64
+ historySize: 80,
65
+ sampling: "diverse",
66
+ includeChangedPathStatistics: true,
67
+ deterministic: false
68
+ }
69
+ ];
70
+ function orderedTasks(tasks) {
71
+ const seen = new Set();
72
+ for (const task of tasks) {
73
+ if (task.caseId.trim().length === 0 || seen.has(task.caseId)) {
74
+ throw new Error("basis tasks require non-empty unique case IDs");
75
+ }
76
+ if (!Number.isFinite(Date.parse(task.occurredAt))) {
77
+ throw new Error(`basis task ${JSON.stringify(task.caseId)} has an invalid occurredAt`);
78
+ }
79
+ seen.add(task.caseId);
80
+ }
81
+ return [...tasks].sort((left, right) => Date.parse(left.occurredAt) - Date.parse(right.occurredAt) ||
82
+ left.caseId.localeCompare(right.caseId));
83
+ }
84
+ /**
85
+ * Freezes oldest→newest construction/validation/final cohorts.
86
+ *
87
+ * The default keeps 12 validation and 28 final tasks whenever at least one
88
+ * older construction task remains. Sparse histories fail closed with explicit
89
+ * provisional/no-final warnings rather than borrowing from held-out cohorts.
90
+ */
91
+ export function splitBasisTasksChronologicallyV3(tasks, input = {}) {
92
+ const ordered = orderedTasks(tasks);
93
+ const requestedValidation = input.validationCount ?? 12;
94
+ const requestedFinal = input.finalCount ?? 28;
95
+ if (!Number.isSafeInteger(requestedValidation) ||
96
+ requestedValidation < 1 ||
97
+ !Number.isSafeInteger(requestedFinal) ||
98
+ requestedFinal < 1) {
99
+ throw new Error("basis split counts must be positive integers");
100
+ }
101
+ const validationCount = Math.min(requestedValidation, Math.max(0, ordered.length - 1));
102
+ const finalCount = Math.min(requestedFinal, Math.max(0, ordered.length - validationCount - 1));
103
+ const constructionCount = ordered.length - validationCount - finalCount;
104
+ const construction = ordered.slice(0, constructionCount);
105
+ const validation = ordered.slice(constructionCount, constructionCount + validationCount);
106
+ const final = ordered.slice(constructionCount + validationCount);
107
+ const warnings = [
108
+ ...(validation.length < requestedValidation
109
+ ? [
110
+ `validation cohort contains ${String(validation.length)} tasks; ${String(requestedValidation)} are required for non-provisional selection`
111
+ ]
112
+ : []),
113
+ ...(final.length < requestedFinal
114
+ ? [
115
+ `final cohort contains ${String(final.length)} tasks; ${String(requestedFinal)} are required for the default launch qualification`
116
+ ]
117
+ : []),
118
+ ...(final.length === 0
119
+ ? ["no untouched final cohort is available; production qualification is prohibited"]
120
+ : [])
121
+ ];
122
+ const semantic = {
123
+ version: 1,
124
+ construction,
125
+ validation,
126
+ final,
127
+ provisional: validation.length < requestedValidation,
128
+ warnings
129
+ };
130
+ return {
131
+ ...semantic,
132
+ splitDigest: routingContractDigest("routekit.basis-task-split.v1", "split", semantic)
133
+ };
134
+ }
135
+ export function selectConstructionTasksForRecipeV3(split, recipe) {
136
+ if (recipe.historySize === 0)
137
+ return [];
138
+ const construction = [...split.construction];
139
+ if (construction.length <= recipe.historySize)
140
+ return construction;
141
+ if (recipe.sampling === "recent") {
142
+ return construction.slice(-recipe.historySize);
143
+ }
144
+ if (recipe.sampling !== "diverse") {
145
+ throw new Error(`recipe ${JSON.stringify(recipe.id)} has an invalid history sampling mode`);
146
+ }
147
+ if (recipe.historySize === 1)
148
+ return [construction[0]];
149
+ const selected = new Map();
150
+ for (let index = 0; index < recipe.historySize; index += 1) {
151
+ const position = Math.round((index * (construction.length - 1)) / (recipe.historySize - 1));
152
+ const task = construction[position];
153
+ selected.set(task.caseId, task);
154
+ }
155
+ return [...selected.values()].sort((left, right) => Date.parse(left.occurredAt) - Date.parse(right.occurredAt) ||
156
+ left.caseId.localeCompare(right.caseId));
157
+ }
@@ -0,0 +1,9 @@
1
+ import { type RoutingBasisV3, type RoutingDimensionDefinitionV3, type WorkloadDimension } from "@velum-labs/routekit-eval-contracts";
2
+ import type { BasisEvaluationProjectionV3 } from "./project-contracts.js";
3
+ /**
4
+ * Projects the approved V3 semantic basis into the existing evaluator/scorer
5
+ * dimension vocabulary. The projection is derived, immutable, and never an
6
+ * independently editable routing basis.
7
+ */
8
+ export declare function projectRoutingDimensionV3(dimension: RoutingDimensionDefinitionV3): WorkloadDimension;
9
+ export declare function projectRoutingBasisV3(basis: RoutingBasisV3): BasisEvaluationProjectionV3;
@@ -0,0 +1,30 @@
1
+ import { assertRoutingBasis } from "@velum-labs/routekit-eval-contracts";
2
+ import { routingBasisDigest } from "./project-artifacts.js";
3
+ /**
4
+ * Projects the approved V3 semantic basis into the existing evaluator/scorer
5
+ * dimension vocabulary. The projection is derived, immutable, and never an
6
+ * independently editable routing basis.
7
+ */
8
+ export function projectRoutingDimensionV3(dimension) {
9
+ return {
10
+ id: dimension.id,
11
+ description: dimension.description,
12
+ includes: dimension.inclusions,
13
+ excludes: dimension.exclusions
14
+ };
15
+ }
16
+ export function projectRoutingBasisV3(basis) {
17
+ const dimensions = basis.dimensions.map(projectRoutingDimensionV3);
18
+ const projected = {
19
+ version: 2,
20
+ basisDigest: routingBasisDigest(dimensions),
21
+ dimensions
22
+ };
23
+ assertRoutingBasis(projected);
24
+ return {
25
+ version: 1,
26
+ basisDigest: basis.basisDigest,
27
+ projectedBasisDigest: projected.basisDigest,
28
+ dimensions: projected.dimensions
29
+ };
30
+ }
@@ -0,0 +1,38 @@
1
+ import { type DimensionScoreLabelV3, type DimensionScorePredictionV3, type RoutingBasisApprovalV3 } from "@velum-labs/routekit-eval-contracts";
2
+ import type { BasisCandidateDatasetV3, BasisCandidateRecordV3, BasisLabelProtocolV3, BasisSelectionReportV3, BasisStructureReportV3, BasisTaskRecordV3, BasisValidationPlanV3, BasisValidationResultV3, FrozenRepositorySnapshotV3 } from "./project-contracts.js";
3
+ export declare function inspectBasisCandidatesV3(candidates: readonly BasisCandidateRecordV3[], aliasSimilarityThreshold?: number): readonly BasisStructureReportV3[];
4
+ export declare function makeBasisCandidateDatasetV3(input: {
5
+ readonly splitDigest: string;
6
+ readonly candidate: BasisCandidateRecordV3;
7
+ readonly tasks: readonly BasisTaskRecordV3[];
8
+ readonly labelProtocol: BasisLabelProtocolV3;
9
+ readonly labels: readonly DimensionScoreLabelV3[];
10
+ }): BasisCandidateDatasetV3;
11
+ export declare function evaluateBasisCandidateValidationV3(input: {
12
+ readonly candidate: BasisCandidateRecordV3;
13
+ readonly dataset: BasisCandidateDatasetV3;
14
+ readonly validationPlan: BasisValidationPlanV3;
15
+ readonly predictions: readonly DimensionScorePredictionV3[];
16
+ readonly provisional: boolean;
17
+ }): BasisValidationResultV3;
18
+ export declare function selectValidatedBasisCandidatesV3(input: {
19
+ readonly repositoryDigest: string;
20
+ readonly validationPlan: BasisValidationPlanV3;
21
+ readonly candidates: readonly BasisCandidateRecordV3[];
22
+ readonly structureReports: readonly BasisStructureReportV3[];
23
+ readonly validationResults: readonly BasisValidationResultV3[];
24
+ }): BasisSelectionReportV3;
25
+ export declare function approveSelectedBasisV3(input: {
26
+ readonly projectId: string;
27
+ readonly approvedBy: string;
28
+ readonly approvedAt: string;
29
+ readonly snapshot: FrozenRepositorySnapshotV3;
30
+ readonly candidate: BasisCandidateRecordV3;
31
+ readonly structure: BasisStructureReportV3;
32
+ readonly validation: BasisValidationResultV3;
33
+ readonly selection: BasisSelectionReportV3;
34
+ readonly provisionalAcknowledgement?: string;
35
+ }): {
36
+ readonly approval: RoutingBasisApprovalV3;
37
+ readonly approvalDigest: string;
38
+ };