@sanity/ailf 0.4.1 → 1.0.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/config/features.ts +23 -0
- package/config/models.ts +83 -0
- package/config/prompts.ts +16 -0
- package/config/rubrics.ts +225 -0
- package/config/schedules.ts +47 -0
- package/config/sinks.ts +37 -0
- package/config/sources.ts +21 -0
- package/config/thresholds.ts +61 -0
- package/dist/_vendor/ailf-core/config-helpers.d.ts +174 -0
- package/dist/_vendor/ailf-core/config-helpers.js +150 -0
- package/dist/_vendor/ailf-core/env-helper.d.ts +35 -0
- package/dist/_vendor/ailf-core/env-helper.js +45 -0
- package/dist/_vendor/ailf-core/examples/index.d.ts +10 -10
- package/dist/_vendor/ailf-core/examples/index.js +10 -10
- package/dist/_vendor/ailf-core/index.d.ts +3 -0
- package/dist/_vendor/ailf-core/index.js +5 -0
- package/dist/_vendor/ailf-core/ports/context.d.ts +15 -2
- package/dist/_vendor/ailf-core/ports/doc-fetcher.d.ts +2 -2
- package/dist/_vendor/ailf-core/ports/index.d.ts +2 -1
- package/dist/_vendor/ailf-core/ports/mode-handler.d.ts +129 -0
- package/dist/_vendor/ailf-core/ports/mode-handler.js +19 -0
- package/dist/_vendor/ailf-core/ports/task-source.d.ts +16 -122
- package/dist/_vendor/ailf-core/ports/task-source.js +7 -7
- package/dist/_vendor/ailf-core/schemas/eval-config.d.ts +7 -2
- package/dist/_vendor/ailf-core/schemas/eval-config.js +7 -2
- package/dist/_vendor/ailf-core/schemas/pipeline-request.d.ts +8 -3
- package/dist/_vendor/ailf-core/schemas/pipeline-request.js +6 -1
- package/dist/_vendor/ailf-core/schemas/pipeline.d.ts +32 -31
- package/dist/_vendor/ailf-core/schemas/pipeline.js +52 -12
- package/dist/_vendor/ailf-core/schemas/schedules.d.ts +14 -4
- package/dist/_vendor/ailf-core/schemas/schedules.js +6 -2
- package/dist/_vendor/ailf-core/schemas/sinks.d.ts +1 -1
- package/dist/_vendor/ailf-core/services/comparison-formatters.js +57 -19
- package/dist/_vendor/ailf-core/services/index.d.ts +2 -1
- package/dist/_vendor/ailf-core/services/index.js +2 -1
- package/dist/_vendor/ailf-core/services/scoring-engine.d.ts +153 -0
- package/dist/_vendor/ailf-core/services/scoring-engine.js +237 -0
- package/dist/_vendor/ailf-core/services/scoring.d.ts +15 -2
- package/dist/_vendor/ailf-core/services/scoring.js +25 -15
- package/dist/_vendor/ailf-core/types/branded-ids.d.ts +137 -0
- package/dist/_vendor/ailf-core/types/branded-ids.js +136 -0
- package/dist/_vendor/ailf-core/types/eval-mode-config.d.ts +150 -0
- package/dist/_vendor/ailf-core/types/eval-mode-config.js +24 -0
- package/dist/_vendor/ailf-core/types/generalized-task.d.ts +319 -0
- package/dist/_vendor/ailf-core/types/generalized-task.js +13 -0
- package/dist/_vendor/ailf-core/types/index.d.ts +45 -81
- package/dist/_vendor/ailf-core/types/index.js +8 -1
- package/dist/_vendor/ailf-core/types/plugin-registry.d.ts +202 -0
- package/dist/_vendor/ailf-core/types/plugin-registry.js +132 -0
- package/dist/_vendor/ailf-core/types/storage-schema.d.ts +199 -0
- package/dist/_vendor/ailf-core/types/storage-schema.js +39 -0
- package/dist/_vendor/ailf-core/types/task-graph.d.ts +86 -0
- package/dist/_vendor/ailf-core/types/task-graph.js +20 -0
- package/dist/_vendor/ailf-core/types/trace.d.ts +118 -0
- package/dist/_vendor/ailf-core/types/trace.js +18 -0
- package/dist/_vendor/ailf-core/types/variable-envelope.d.ts +80 -0
- package/dist/_vendor/ailf-core/types/variable-envelope.js +16 -0
- package/dist/_vendor/ailf-shared/dimension-names.d.ts +5 -18
- package/dist/_vendor/ailf-shared/dimension-names.js +6 -24
- package/dist/_vendor/ailf-shared/eval-modes.d.ts +38 -6
- package/dist/_vendor/ailf-shared/eval-modes.js +26 -2
- package/dist/_vendor/ailf-shared/index.d.ts +0 -1
- package/dist/_vendor/ailf-shared/index.js +0 -1
- package/dist/adapters/api-client/build-request.js +14 -13
- package/dist/adapters/config-sources/file-config-adapter.d.ts +20 -11
- package/dist/adapters/config-sources/file-config-adapter.js +38 -12
- package/dist/adapters/config-sources/index.d.ts +2 -0
- package/dist/adapters/config-sources/index.js +1 -0
- package/dist/adapters/config-sources/ts-config-loader.d.ts +59 -0
- package/dist/adapters/config-sources/ts-config-loader.js +133 -0
- package/dist/adapters/doc-fetchers/sanity-doc-fetcher.d.ts +3 -2
- package/dist/adapters/doc-fetchers/sanity-doc-fetcher.js +7 -2
- package/dist/adapters/task-sources/composite-task-source.d.ts +3 -3
- package/dist/adapters/task-sources/composite-task-source.js +1 -1
- package/dist/adapters/task-sources/content-lake-task-source.d.ts +7 -6
- package/dist/adapters/task-sources/content-lake-task-source.js +22 -23
- package/dist/adapters/task-sources/index.d.ts +1 -0
- package/dist/adapters/task-sources/index.js +1 -0
- package/dist/adapters/task-sources/repo-task-source.d.ts +4 -4
- package/dist/adapters/task-sources/repo-task-source.js +69 -16
- package/dist/adapters/task-sources/task-file-loader.d.ts +64 -0
- package/dist/adapters/task-sources/task-file-loader.js +83 -0
- package/dist/adapters/task-sources/yaml-task-source.d.ts +6 -6
- package/dist/adapters/task-sources/yaml-task-source.js +19 -16
- package/dist/cli.js +0 -2
- package/dist/commands/baseline.js +4 -1
- package/dist/commands/calculate-scores.js +1 -1
- package/dist/commands/coverage-audit.js +7 -1
- package/dist/commands/explain-handler.js +25 -23
- package/dist/commands/fetch-docs.js +3 -2
- package/dist/commands/generate-configs.js +1 -1
- package/dist/commands/interactive.js +11 -7
- package/dist/commands/pipeline-action.d.ts +2 -0
- package/dist/commands/pipeline-action.js +16 -6
- package/dist/commands/pipeline.d.ts +1 -0
- package/dist/commands/pipeline.js +4 -2
- package/dist/commands/pr-comment.js +1 -1
- package/dist/commands/publish.js +2 -2
- package/dist/commands/readiness-report.js +13 -6
- package/dist/composition-root.d.ts +1 -1
- package/dist/composition-root.js +67 -4
- package/dist/orchestration/build-app-context.js +1 -0
- package/dist/orchestration/build-step-sequence.js +24 -6
- package/dist/orchestration/steps/calculate-scores-step.js +24 -11
- package/dist/orchestration/steps/fetch-docs-step.js +6 -4
- package/dist/orchestration/steps/gap-analysis-step.js +8 -7
- package/dist/orchestration/steps/generate-configs-step.d.ts +16 -3
- package/dist/orchestration/steps/generate-configs-step.js +245 -51
- package/dist/orchestration/steps/grader-consistency-step.js +7 -4
- package/dist/orchestration/steps/mirror-repo-tasks-step.js +1 -1
- package/dist/orchestration/steps/readiness-step.js +5 -6
- package/dist/orchestration/steps/run-eval-step.d.ts +1 -2
- package/dist/orchestration/steps/run-eval-step.js +8 -7
- package/dist/pipeline/cache.d.ts +1 -1
- package/dist/pipeline/cache.js +36 -8
- package/dist/pipeline/calculate-scores.d.ts +5 -7
- package/dist/pipeline/calculate-scores.js +74 -153
- package/dist/pipeline/checks.js +2 -2
- package/dist/pipeline/compare.js +8 -8
- package/dist/pipeline/compiler/__tests__/agent-harness-handler.test.d.ts +10 -0
- package/dist/pipeline/compiler/__tests__/agent-harness-handler.test.js +288 -0
- package/dist/pipeline/compiler/__tests__/assertion-mapper.test.d.ts +9 -0
- package/dist/pipeline/compiler/__tests__/assertion-mapper.test.js +145 -0
- package/dist/pipeline/compiler/__tests__/knowledge-probe-handler.test.d.ts +10 -0
- package/dist/pipeline/compiler/__tests__/knowledge-probe-handler.test.js +314 -0
- package/dist/pipeline/compiler/__tests__/literacy-handler.test.d.ts +10 -0
- package/dist/pipeline/compiler/__tests__/literacy-handler.test.js +486 -0
- package/dist/pipeline/compiler/__tests__/mcp-server-handler.test.d.ts +10 -0
- package/dist/pipeline/compiler/__tests__/mcp-server-handler.test.js +355 -0
- package/dist/pipeline/compiler/__tests__/promptfoo-compiler.test.d.ts +9 -0
- package/dist/pipeline/compiler/__tests__/promptfoo-compiler.test.js +333 -0
- package/dist/pipeline/compiler/__tests__/sandbox-and-fixtures.test.d.ts +12 -0
- package/dist/pipeline/compiler/__tests__/sandbox-and-fixtures.test.js +210 -0
- package/dist/pipeline/compiler/__tests__/scoring-and-presets.test.d.ts +7 -0
- package/dist/pipeline/compiler/__tests__/scoring-and-presets.test.js +471 -0
- package/dist/pipeline/compiler/__tests__/scoring-bridge.test.d.ts +10 -0
- package/dist/pipeline/compiler/__tests__/scoring-bridge.test.js +184 -0
- package/dist/pipeline/compiler/__tests__/task-graph-builder.test.d.ts +8 -0
- package/dist/pipeline/compiler/__tests__/task-graph-builder.test.js +301 -0
- package/dist/pipeline/compiler/__tests__/telemetry.test.d.ts +9 -0
- package/dist/pipeline/compiler/__tests__/telemetry.test.js +503 -0
- package/dist/pipeline/compiler/assertion-mapper.d.ts +58 -0
- package/dist/pipeline/compiler/assertion-mapper.js +175 -0
- package/dist/pipeline/compiler/compiler-to-yaml.d.ts +51 -0
- package/dist/pipeline/compiler/compiler-to-yaml.js +222 -0
- package/dist/pipeline/compiler/config-loader.d.ts +56 -0
- package/dist/pipeline/compiler/config-loader.js +111 -0
- package/dist/pipeline/compiler/fixture-resolver.d.ts +41 -0
- package/dist/pipeline/compiler/fixture-resolver.js +113 -0
- package/dist/pipeline/compiler/hash.d.ts +11 -0
- package/dist/pipeline/compiler/hash.js +18 -0
- package/dist/pipeline/compiler/ignore-fields.d.ts +53 -0
- package/dist/pipeline/compiler/ignore-fields.js +113 -0
- package/dist/pipeline/compiler/index.d.ts +29 -0
- package/dist/pipeline/compiler/index.js +45 -0
- package/dist/pipeline/compiler/literacy-bridge.d.ts +102 -0
- package/dist/pipeline/compiler/literacy-bridge.js +172 -0
- package/dist/pipeline/compiler/mode-handlers/__fixtures__/agent-harness-example-tasks.d.ts +14 -0
- package/dist/pipeline/compiler/mode-handlers/__fixtures__/agent-harness-example-tasks.js +152 -0
- package/dist/pipeline/compiler/mode-handlers/__fixtures__/knowledge-probe-example-tasks.d.ts +32 -0
- package/dist/pipeline/compiler/mode-handlers/__fixtures__/knowledge-probe-example-tasks.js +176 -0
- package/dist/pipeline/compiler/mode-handlers/__fixtures__/mcp-example-tasks.d.ts +49 -0
- package/dist/pipeline/compiler/mode-handlers/__fixtures__/mcp-example-tasks.js +259 -0
- package/dist/pipeline/compiler/mode-handlers/agent-harness-handler.d.ts +70 -0
- package/dist/pipeline/compiler/mode-handlers/agent-harness-handler.js +485 -0
- package/dist/pipeline/compiler/mode-handlers/index.d.ts +16 -0
- package/dist/pipeline/compiler/mode-handlers/index.js +21 -0
- package/dist/pipeline/compiler/mode-handlers/knowledge-probe-handler.d.ts +76 -0
- package/dist/pipeline/compiler/mode-handlers/knowledge-probe-handler.js +245 -0
- package/dist/pipeline/compiler/mode-handlers/literacy-handler.d.ts +89 -0
- package/dist/pipeline/compiler/mode-handlers/literacy-handler.js +379 -0
- package/dist/pipeline/compiler/mode-handlers/mcp-assertions.d.ts +50 -0
- package/dist/pipeline/compiler/mode-handlers/mcp-assertions.js +277 -0
- package/dist/pipeline/compiler/mode-handlers/mcp-server-handler.d.ts +67 -0
- package/dist/pipeline/compiler/mode-handlers/mcp-server-handler.js +309 -0
- package/dist/pipeline/compiler/presets/index.d.ts +9 -0
- package/dist/pipeline/compiler/presets/index.js +8 -0
- package/dist/pipeline/compiler/presets/sanity-literacy.d.ts +45 -0
- package/dist/pipeline/compiler/presets/sanity-literacy.js +354 -0
- package/dist/pipeline/compiler/promptfoo-compiler.d.ts +96 -0
- package/dist/pipeline/compiler/promptfoo-compiler.js +230 -0
- package/dist/pipeline/compiler/provider-assembler.d.ts +39 -0
- package/dist/pipeline/compiler/provider-assembler.js +137 -0
- package/dist/pipeline/compiler/sandbox/docker-sandbox.d.ts +21 -0
- package/dist/pipeline/compiler/sandbox/docker-sandbox.js +136 -0
- package/dist/pipeline/compiler/sandbox/fixture-provisioner.d.ts +69 -0
- package/dist/pipeline/compiler/sandbox/fixture-provisioner.js +189 -0
- package/dist/pipeline/compiler/sandbox/git-worktree-sandbox.d.ts +20 -0
- package/dist/pipeline/compiler/sandbox/git-worktree-sandbox.js +114 -0
- package/dist/pipeline/compiler/sandbox/index.d.ts +10 -0
- package/dist/pipeline/compiler/sandbox/index.js +11 -0
- package/dist/pipeline/compiler/sandbox/sandbox-selector.d.ts +35 -0
- package/dist/pipeline/compiler/sandbox/sandbox-selector.js +86 -0
- package/dist/pipeline/compiler/sandbox/sandbox-strategy.d.ts +81 -0
- package/dist/pipeline/compiler/sandbox/sandbox-strategy.js +15 -0
- package/dist/pipeline/compiler/sandbox/tempdir-sandbox.d.ts +20 -0
- package/dist/pipeline/compiler/sandbox/tempdir-sandbox.js +74 -0
- package/dist/pipeline/compiler/scoring-bridge.d.ts +49 -0
- package/dist/pipeline/compiler/scoring-bridge.js +114 -0
- package/dist/pipeline/compiler/task-graph-builder.d.ts +54 -0
- package/dist/pipeline/compiler/task-graph-builder.js +291 -0
- package/dist/pipeline/compiler/telemetry/cost-tracker.d.ts +90 -0
- package/dist/pipeline/compiler/telemetry/cost-tracker.js +146 -0
- package/dist/pipeline/compiler/telemetry/index.d.ts +14 -0
- package/dist/pipeline/compiler/telemetry/index.js +19 -0
- package/dist/pipeline/compiler/telemetry/redactor.d.ts +58 -0
- package/dist/pipeline/compiler/telemetry/redactor.js +222 -0
- package/dist/pipeline/compiler/telemetry/tool-classifier.d.ts +32 -0
- package/dist/pipeline/compiler/telemetry/tool-classifier.js +120 -0
- package/dist/pipeline/compiler/telemetry/trace-collector.d.ts +75 -0
- package/dist/pipeline/compiler/telemetry/trace-collector.js +297 -0
- package/dist/pipeline/compiler/telemetry/trace-store.d.ts +78 -0
- package/dist/pipeline/compiler/telemetry/trace-store.js +85 -0
- package/dist/pipeline/compiler/variable-resolver.d.ts +46 -0
- package/dist/pipeline/compiler/variable-resolver.js +115 -0
- package/dist/pipeline/coverage-audit.d.ts +15 -5
- package/dist/pipeline/coverage-audit.js +41 -22
- package/dist/pipeline/eval-constants.d.ts +16 -6
- package/dist/pipeline/eval-constants.js +25 -4
- package/dist/pipeline/eval-fingerprint.d.ts +2 -2
- package/dist/pipeline/eval-fingerprint.js +8 -9
- package/dist/pipeline/expand-tasks.d.ts +23 -14
- package/dist/pipeline/expand-tasks.js +37 -31
- package/dist/pipeline/gap-analysis.d.ts +1 -1
- package/dist/pipeline/gap-analysis.js +2 -2
- package/dist/pipeline/generate-configs.d.ts +22 -4
- package/dist/pipeline/generate-configs.js +53 -24
- package/dist/pipeline/grader-api.d.ts +3 -3
- package/dist/pipeline/grader-api.js +5 -12
- package/dist/pipeline/grader-compare-runner.js +20 -27
- package/dist/pipeline/grader-comparison.d.ts +4 -8
- package/dist/pipeline/grader-comparison.js +11 -17
- package/dist/pipeline/grader-consistency-runner.d.ts +2 -3
- package/dist/pipeline/grader-consistency-runner.js +18 -21
- package/dist/pipeline/grader-consistency.d.ts +6 -10
- package/dist/pipeline/grader-consistency.js +13 -32
- package/dist/pipeline/grader-sensitivity-runner.js +7 -5
- package/dist/pipeline/grader-sensitivity.d.ts +2 -6
- package/dist/pipeline/grader-sensitivity.js +10 -10
- package/dist/pipeline/grader-validate-runner.js +7 -5
- package/dist/pipeline/grader-validation.d.ts +2 -6
- package/dist/pipeline/grader-validation.js +14 -22
- package/dist/pipeline/map-request-to-config.js +6 -1
- package/dist/pipeline/mirror-repo-tasks.d.ts +6 -6
- package/dist/pipeline/mirror-repo-tasks.js +16 -15
- package/dist/pipeline/normalize-mode.d.ts +49 -0
- package/dist/pipeline/normalize-mode.js +64 -0
- package/dist/pipeline/plan.d.ts +5 -2
- package/dist/pipeline/plan.js +134 -78
- package/dist/pipeline/pr-comment.js +2 -0
- package/dist/pipeline/profile-resolution.d.ts +47 -0
- package/dist/pipeline/profile-resolution.js +91 -0
- package/dist/pipeline/provenance.d.ts +2 -2
- package/dist/pipeline/provenance.js +12 -17
- package/dist/pipeline/release-report.js +4 -4
- package/dist/pipeline/repo-threshold-evaluator.d.ts +1 -1
- package/dist/pipeline/repo-threshold-evaluator.js +1 -1
- package/dist/pipeline/rubric-loader.d.ts +20 -0
- package/dist/pipeline/rubric-loader.js +37 -0
- package/dist/pipeline/validate.d.ts +4 -4
- package/dist/pipeline/validate.js +64 -53
- package/dist/schedules/loader.js +18 -8
- package/dist/scripts/migrate-task-mode.d.ts +24 -0
- package/dist/scripts/migrate-task-mode.js +85 -0
- package/dist/scripts/migrate-tasks-to-content-lake.js +11 -10
- package/dist/scripts/validate-task-sources.d.ts +1 -1
- package/dist/scripts/validate-task-sources.js +15 -15
- package/dist/sinks/loader.js +5 -7
- package/dist/sources.d.ts +7 -7
- package/dist/sources.js +22 -24
- package/dist/webhook/dispatch.js +2 -1
- package/package.json +6 -3
- package/tasks/knowledge-probe/define-type-api.task.ts +55 -0
- package/tasks/knowledge-probe/groq-projections.task.ts +59 -0
- package/tasks/literacy/frameworks.task.ts +128 -0
- package/tasks/literacy/functions.task.ts +69 -0
- package/tasks/literacy/groq.task.ts +258 -0
- package/tasks/literacy/nextjs-live.task.ts +75 -0
- package/tasks/literacy/studio-setup.task.ts +131 -0
- package/tasks/literacy/visual-editing.task.ts +146 -0
- package/config/features.yaml +0 -116
- package/config/models.yaml +0 -116
- package/config/prompts.yaml +0 -75
- package/config/rubrics.yaml +0 -62
- package/config/schedules.yaml +0 -43
- package/config/sinks.yaml +0 -54
- package/config/sources.yaml +0 -51
- package/config/thresholds.yaml +0 -49
- package/dist/agent-observer/test-imports.d.ts +0 -7
- package/dist/agent-observer/test-imports.js +0 -185
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import fs from "fs";
|
|
11
11
|
import path from "path";
|
|
12
12
|
import { load } from "js-yaml";
|
|
13
|
+
import { tryLoadConfigFile } from "./compiler/config-loader.js";
|
|
13
14
|
import { resolveMappings } from "./resolve-mappings.js";
|
|
14
15
|
import { FeatureRegistrySchema, formatZodErrors, RubricConfigSchema, TaskFileSchema, ThresholdConfigSchema, } from "./schemas.js";
|
|
15
16
|
// ---------------------------------------------------------------------------
|
|
@@ -64,7 +65,7 @@ export function validateContexts(rootDir) {
|
|
|
64
65
|
return issues;
|
|
65
66
|
}
|
|
66
67
|
/**
|
|
67
|
-
* Check that config/features
|
|
68
|
+
* Check that config/features exists, parses, and conforms to the Zod schema.
|
|
68
69
|
* Also cross-references covered features against actual task files for consistency.
|
|
69
70
|
*
|
|
70
71
|
* Returns warnings (not errors) if the file is missing — the feature registry
|
|
@@ -73,20 +74,24 @@ export function validateContexts(rootDir) {
|
|
|
73
74
|
export function validateFeaturesYaml(rootDir) {
|
|
74
75
|
const source = "validateFeaturesYaml";
|
|
75
76
|
const issues = [];
|
|
76
|
-
const
|
|
77
|
-
if (!
|
|
77
|
+
const loaded = tryLoadConfigFile("features", rootDir);
|
|
78
|
+
if (!loaded) {
|
|
78
79
|
// Feature registry is optional — warn, don't error
|
|
79
|
-
issues.push(warning(source, "config/features
|
|
80
|
+
issues.push(warning(source, "config/features not found — coverage audit unavailable", path.join(rootDir, "config")));
|
|
81
|
+
return issues;
|
|
82
|
+
}
|
|
83
|
+
// Empty features array is valid — it means features come from the preset.
|
|
84
|
+
// The Zod schema requires .min(1) for non-empty configs, but an empty
|
|
85
|
+
// stub is the expected state when the preset provides all features.
|
|
86
|
+
const raw = loaded.data;
|
|
87
|
+
if (Array.isArray(raw?.features) && raw.features.length === 0) {
|
|
80
88
|
return issues;
|
|
81
89
|
}
|
|
82
|
-
const
|
|
83
|
-
if (!result.ok)
|
|
84
|
-
return [result.issue];
|
|
85
|
-
const zodResult = FeatureRegistrySchema.safeParse(result.data);
|
|
90
|
+
const zodResult = FeatureRegistrySchema.safeParse(loaded.data);
|
|
86
91
|
if (!zodResult.success) {
|
|
87
92
|
const lines = formatZodErrors(zodResult.error);
|
|
88
93
|
for (const line of lines) {
|
|
89
|
-
issues.push(error(source, `config/features
|
|
94
|
+
issues.push(error(source, `config/features: ${line.trim()}`, loaded.filePath));
|
|
90
95
|
}
|
|
91
96
|
return issues;
|
|
92
97
|
}
|
|
@@ -95,18 +100,18 @@ export function validateFeaturesYaml(rootDir) {
|
|
|
95
100
|
if (fs.existsSync(tasksDir)) {
|
|
96
101
|
const taskFiles = new Set(fs
|
|
97
102
|
.readdirSync(tasksDir)
|
|
98
|
-
.filter((f) =>
|
|
99
|
-
.map((f) => f.replace(/\.(yaml|yml)$/, "")));
|
|
103
|
+
.filter((f) => /\.(yaml|yml|task\.ts|task\.js)$/.test(f))
|
|
104
|
+
.map((f) => f.replace(/\.(yaml|yml|task\.ts|task\.js)$/, "")));
|
|
100
105
|
for (const feature of zodResult.data.features) {
|
|
101
106
|
if (feature.status === "covered" && feature.area) {
|
|
102
107
|
if (!taskFiles.has(feature.area)) {
|
|
103
|
-
issues.push(warning(source, `Feature '${feature.id}' is status: covered with area: '${feature.area}', but tasks/${feature.area}
|
|
108
|
+
issues.push(warning(source, `Feature '${feature.id}' is status: covered with area: '${feature.area}', but tasks/${feature.area} does not exist`, loaded.filePath));
|
|
104
109
|
}
|
|
105
110
|
}
|
|
106
111
|
// Warn if an "uncovered" feature has a matching task file
|
|
107
112
|
if (feature.status === "uncovered" && feature.area) {
|
|
108
113
|
if (taskFiles.has(feature.area)) {
|
|
109
|
-
issues.push(warning(source, `Feature '${feature.id}' is status: uncovered but tasks/${feature.area}
|
|
114
|
+
issues.push(warning(source, `Feature '${feature.id}' is status: uncovered but tasks/${feature.area} task file exists — consider updating status to 'covered'`, loaded.filePath));
|
|
110
115
|
}
|
|
111
116
|
}
|
|
112
117
|
}
|
|
@@ -114,7 +119,7 @@ export function validateFeaturesYaml(rootDir) {
|
|
|
114
119
|
const ids = new Set();
|
|
115
120
|
for (const feature of zodResult.data.features) {
|
|
116
121
|
if (ids.has(feature.id)) {
|
|
117
|
-
issues.push(error(source, `Duplicate feature id '${feature.id}' in config/features
|
|
122
|
+
issues.push(error(source, `Duplicate feature id '${feature.id}' in config/features`, loaded.filePath));
|
|
118
123
|
}
|
|
119
124
|
ids.add(feature.id);
|
|
120
125
|
}
|
|
@@ -122,47 +127,57 @@ export function validateFeaturesYaml(rootDir) {
|
|
|
122
127
|
return issues;
|
|
123
128
|
}
|
|
124
129
|
/**
|
|
125
|
-
* Check that config/models
|
|
130
|
+
* Check that config/models exists, parses, has at least one model with an id
|
|
126
131
|
* and label, and has a grader defined.
|
|
127
132
|
*/
|
|
128
133
|
export function validateModelsYaml(rootDir) {
|
|
129
134
|
const source = "validateModelsYaml";
|
|
130
135
|
const issues = [];
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
+
let data;
|
|
137
|
+
try {
|
|
138
|
+
data = loadConfigFileForValidation("models", rootDir);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
issues.push(error(source, "config/models not found", path.join(rootDir, "config")));
|
|
142
|
+
return issues;
|
|
143
|
+
}
|
|
136
144
|
if (!data || typeof data !== "object") {
|
|
137
|
-
issues.push(error(source, "config/models
|
|
145
|
+
issues.push(error(source, "config/models did not parse to an object", path.join(rootDir, "config")));
|
|
138
146
|
return issues;
|
|
139
147
|
}
|
|
140
148
|
// Check models array
|
|
141
149
|
if (!Array.isArray(data.models)) {
|
|
142
|
-
issues.push(error(source, "config/models
|
|
150
|
+
issues.push(error(source, "config/models is missing a 'models' array", path.join(rootDir, "config")));
|
|
143
151
|
}
|
|
144
152
|
else if (data.models.length === 0) {
|
|
145
|
-
issues.push(error(source, "config/models
|
|
153
|
+
issues.push(error(source, "config/models has an empty 'models' array", path.join(rootDir, "config")));
|
|
146
154
|
}
|
|
147
155
|
else {
|
|
148
156
|
for (const [i, model] of data.models.entries()) {
|
|
149
157
|
if (!model.id) {
|
|
150
|
-
issues.push(error(source, `models[${i}] is missing 'id'`,
|
|
158
|
+
issues.push(error(source, `models[${i}] is missing 'id'`, path.join(rootDir, "config")));
|
|
151
159
|
}
|
|
152
160
|
if (!model.label) {
|
|
153
|
-
issues.push(error(source, `models[${i}] is missing 'label'`,
|
|
161
|
+
issues.push(error(source, `models[${i}] is missing 'label'`, path.join(rootDir, "config")));
|
|
154
162
|
}
|
|
155
163
|
}
|
|
156
164
|
}
|
|
157
165
|
// Check grader
|
|
158
166
|
if (!data.grader) {
|
|
159
|
-
issues.push(error(source, "config/models
|
|
167
|
+
issues.push(error(source, "config/models is missing a 'grader' section", path.join(rootDir, "config")));
|
|
160
168
|
}
|
|
161
169
|
else if (!data.grader.id) {
|
|
162
|
-
issues.push(error(source, "config/models
|
|
170
|
+
issues.push(error(source, "config/models grader is missing 'id'", path.join(rootDir, "config")));
|
|
163
171
|
}
|
|
164
172
|
return issues;
|
|
165
173
|
}
|
|
174
|
+
/** Helper: load a config file for validation (throws on not found) */
|
|
175
|
+
function loadConfigFileForValidation(name, rootDir) {
|
|
176
|
+
const result = tryLoadConfigFile(name, rootDir);
|
|
177
|
+
if (!result)
|
|
178
|
+
throw new Error(`Config "${name}" not found`);
|
|
179
|
+
return result.data;
|
|
180
|
+
}
|
|
166
181
|
// ---------------------------------------------------------------------------
|
|
167
182
|
// Validators
|
|
168
183
|
// ---------------------------------------------------------------------------
|
|
@@ -198,22 +213,23 @@ export function validateReferenceSolutions(rootDir) {
|
|
|
198
213
|
return issues;
|
|
199
214
|
}
|
|
200
215
|
/**
|
|
201
|
-
* Check that config/rubrics
|
|
216
|
+
* Check that config/rubrics exists, parses, and conforms to the Zod schema.
|
|
202
217
|
* Returns the set of valid template keys for cross-referencing by task
|
|
203
218
|
* validation.
|
|
204
219
|
*/
|
|
205
220
|
export function validateRubricsYaml(rootDir) {
|
|
206
221
|
const source = "validateRubricsYaml";
|
|
207
222
|
const issues = [];
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
return
|
|
212
|
-
|
|
223
|
+
const loaded = tryLoadConfigFile("rubrics", rootDir);
|
|
224
|
+
if (!loaded) {
|
|
225
|
+
issues.push(error(source, "config/rubrics not found", path.join(rootDir, "config")));
|
|
226
|
+
return issues;
|
|
227
|
+
}
|
|
228
|
+
const zodResult = RubricConfigSchema.safeParse(loaded.data);
|
|
213
229
|
if (!zodResult.success) {
|
|
214
230
|
const lines = formatZodErrors(zodResult.error);
|
|
215
231
|
for (const line of lines) {
|
|
216
|
-
issues.push(error(source, `config/rubrics
|
|
232
|
+
issues.push(error(source, `config/rubrics: ${line.trim()}`, loaded.filePath));
|
|
217
233
|
}
|
|
218
234
|
}
|
|
219
235
|
return issues;
|
|
@@ -281,7 +297,7 @@ export function validateTaskFiles(rootDir) {
|
|
|
281
297
|
issues.push(warning(source, `${file}: id is '${entry.id}' but docs path is '${vars.docs}' (expected '${expectedPath}')`, filePath));
|
|
282
298
|
}
|
|
283
299
|
}
|
|
284
|
-
// Check that llm-rubric template references exist in config/rubrics
|
|
300
|
+
// Check that llm-rubric template references exist in config/rubrics
|
|
285
301
|
const asserts = entry.assert;
|
|
286
302
|
if (Array.isArray(asserts) && templateKeys.size > 0) {
|
|
287
303
|
for (const a of asserts) {
|
|
@@ -300,7 +316,7 @@ export function validateTaskFiles(rootDir) {
|
|
|
300
316
|
return issues;
|
|
301
317
|
}
|
|
302
318
|
/**
|
|
303
|
-
* Check that config/thresholds
|
|
319
|
+
* Check that config/thresholds exists, parses, and conforms to the Zod schema.
|
|
304
320
|
*
|
|
305
321
|
* Returns warnings (not errors) if the file is missing — thresholds are
|
|
306
322
|
* optional and don't block evaluation. They only activate when
|
|
@@ -309,20 +325,17 @@ export function validateTaskFiles(rootDir) {
|
|
|
309
325
|
export function validateThresholdsYaml(rootDir) {
|
|
310
326
|
const source = "validateThresholdsYaml";
|
|
311
327
|
const issues = [];
|
|
312
|
-
const
|
|
313
|
-
if (!
|
|
328
|
+
const loaded = tryLoadConfigFile("thresholds", rootDir);
|
|
329
|
+
if (!loaded) {
|
|
314
330
|
// Thresholds are optional — warn, don't error
|
|
315
|
-
issues.push(warning(source, "config/thresholds
|
|
331
|
+
issues.push(warning(source, "config/thresholds not found — readiness gates and threshold alerts unavailable", path.join(rootDir, "config")));
|
|
316
332
|
return issues;
|
|
317
333
|
}
|
|
318
|
-
const
|
|
319
|
-
if (!result.ok)
|
|
320
|
-
return [result.issue];
|
|
321
|
-
const zodResult = ThresholdConfigSchema.safeParse(result.data);
|
|
334
|
+
const zodResult = ThresholdConfigSchema.safeParse(loaded.data);
|
|
322
335
|
if (!zodResult.success) {
|
|
323
336
|
const lines = formatZodErrors(zodResult.error);
|
|
324
337
|
for (const line of lines) {
|
|
325
|
-
issues.push(error(source, `config/thresholds
|
|
338
|
+
issues.push(error(source, `config/thresholds: ${line.trim()}`, loaded.filePath));
|
|
326
339
|
}
|
|
327
340
|
return issues;
|
|
328
341
|
}
|
|
@@ -332,11 +345,11 @@ export function validateThresholdsYaml(rootDir) {
|
|
|
332
345
|
if (fs.existsSync(tasksDir)) {
|
|
333
346
|
const taskFiles = new Set(fs
|
|
334
347
|
.readdirSync(tasksDir)
|
|
335
|
-
.filter((f) =>
|
|
336
|
-
.map((f) => f.replace(/\.(yaml|yml)$/, "")));
|
|
348
|
+
.filter((f) => /\.(yaml|yml|task\.ts|task\.js)$/.test(f))
|
|
349
|
+
.map((f) => f.replace(/\.(yaml|yml|task\.ts|task\.js)$/, "")));
|
|
337
350
|
for (const areaName of Object.keys(zodResult.data.areas)) {
|
|
338
351
|
if (!taskFiles.has(areaName)) {
|
|
339
|
-
issues.push(warning(source, `config/thresholds
|
|
352
|
+
issues.push(warning(source, `config/thresholds: area override '${areaName}' has no matching tasks/${areaName}`, loaded.filePath));
|
|
340
353
|
}
|
|
341
354
|
}
|
|
342
355
|
}
|
|
@@ -352,17 +365,15 @@ function error(source, message, filePath) {
|
|
|
352
365
|
};
|
|
353
366
|
}
|
|
354
367
|
/**
|
|
355
|
-
* Load the set of valid rubric template keys from config/rubrics.
|
|
368
|
+
* Load the set of valid rubric template keys from config/rubrics.
|
|
356
369
|
* Returns an empty set if the file is missing or invalid.
|
|
357
370
|
*/
|
|
358
371
|
function loadTemplateKeys(rootDir) {
|
|
359
|
-
const
|
|
360
|
-
if (!
|
|
372
|
+
const loaded = tryLoadConfigFile("rubrics", rootDir);
|
|
373
|
+
if (!loaded)
|
|
361
374
|
return new Set();
|
|
362
375
|
try {
|
|
363
|
-
const
|
|
364
|
-
const parsed = load(raw);
|
|
365
|
-
const templates = parsed?.templates;
|
|
376
|
+
const templates = loaded.data?.templates;
|
|
366
377
|
if (templates && typeof templates === "object") {
|
|
367
378
|
return new Set(Object.keys(templates));
|
|
368
379
|
}
|
package/dist/schedules/loader.js
CHANGED
|
@@ -14,12 +14,13 @@ import { dirname, resolve } from "path";
|
|
|
14
14
|
import { fileURLToPath } from "url";
|
|
15
15
|
import { load } from "js-yaml";
|
|
16
16
|
import { interpolate } from "../interpolate.js";
|
|
17
|
+
import { tryLoadConfigFile } from "../pipeline/compiler/config-loader.js";
|
|
17
18
|
import { SchedulesFileSchema, } from "./schema.js";
|
|
18
19
|
// ---------------------------------------------------------------------------
|
|
19
20
|
// Paths
|
|
20
21
|
// ---------------------------------------------------------------------------
|
|
21
22
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
22
|
-
const
|
|
23
|
+
const PACKAGE_ROOT = resolve(__dirname, "..", "..");
|
|
23
24
|
// ---------------------------------------------------------------------------
|
|
24
25
|
// Public API
|
|
25
26
|
// ---------------------------------------------------------------------------
|
|
@@ -56,14 +57,23 @@ export function getEnabledSchedules(configPath) {
|
|
|
56
57
|
* @param configPath - Override the default config file location
|
|
57
58
|
* @returns Parsed and validated schedules file, or null if not found/invalid
|
|
58
59
|
*/
|
|
59
|
-
export function loadSchedules(configPath
|
|
60
|
-
if (!existsSync(configPath)) {
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
60
|
+
export function loadSchedules(configPath) {
|
|
63
61
|
try {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
let data;
|
|
63
|
+
if (configPath) {
|
|
64
|
+
// Explicit path override (used by tests) — read directly
|
|
65
|
+
if (!existsSync(configPath))
|
|
66
|
+
return null;
|
|
67
|
+
data = load(readFileSync(configPath, "utf-8"));
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// Default: use unified config loader
|
|
71
|
+
const loaded = tryLoadConfigFile("schedules", PACKAGE_ROOT);
|
|
72
|
+
if (!loaded)
|
|
73
|
+
return null;
|
|
74
|
+
data = loaded.data;
|
|
75
|
+
}
|
|
76
|
+
const interpolated = interpolate(data);
|
|
67
77
|
return SchedulesFileSchema.parse(interpolated);
|
|
68
78
|
}
|
|
69
79
|
catch (error) {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Migration script: Add mode: "literacy" to Content Lake task documents.
|
|
4
|
+
*
|
|
5
|
+
* Phase 7f of the Architecture Overhaul. Queries all ailf.task documents
|
|
6
|
+
* that lack an explicit `mode` field and patches them with
|
|
7
|
+
* `mode: "literacy"` (the default mode for existing tasks).
|
|
8
|
+
*
|
|
9
|
+
* Idempotent — the GROQ query only matches documents where
|
|
10
|
+
* `!defined(mode)`, so re-running has no effect on already-patched
|
|
11
|
+
* documents.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* cd packages/eval
|
|
15
|
+
* npx tsx src/scripts/migrate-task-mode.ts --dry-run
|
|
16
|
+
* npx tsx src/scripts/migrate-task-mode.ts
|
|
17
|
+
*
|
|
18
|
+
* Prerequisites:
|
|
19
|
+
* - SANITY_API_TOKEN with write access to the project
|
|
20
|
+
* - SANITY_PROJECT_ID and SANITY_DATASET configured (or defaults used)
|
|
21
|
+
*
|
|
22
|
+
* @see docs/exec-plans/architecture-overhaul/phase-7-migrate-literacy.md
|
|
23
|
+
*/
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Migration script: Add mode: "literacy" to Content Lake task documents.
|
|
4
|
+
*
|
|
5
|
+
* Phase 7f of the Architecture Overhaul. Queries all ailf.task documents
|
|
6
|
+
* that lack an explicit `mode` field and patches them with
|
|
7
|
+
* `mode: "literacy"` (the default mode for existing tasks).
|
|
8
|
+
*
|
|
9
|
+
* Idempotent — the GROQ query only matches documents where
|
|
10
|
+
* `!defined(mode)`, so re-running has no effect on already-patched
|
|
11
|
+
* documents.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* cd packages/eval
|
|
15
|
+
* npx tsx src/scripts/migrate-task-mode.ts --dry-run
|
|
16
|
+
* npx tsx src/scripts/migrate-task-mode.ts
|
|
17
|
+
*
|
|
18
|
+
* Prerequisites:
|
|
19
|
+
* - SANITY_API_TOKEN with write access to the project
|
|
20
|
+
* - SANITY_PROJECT_ID and SANITY_DATASET configured (or defaults used)
|
|
21
|
+
*
|
|
22
|
+
* @see docs/exec-plans/architecture-overhaul/phase-7-migrate-literacy.md
|
|
23
|
+
*/
|
|
24
|
+
import { config as dotenvConfig } from "dotenv";
|
|
25
|
+
import { existsSync } from "fs";
|
|
26
|
+
import { dirname, resolve } from "path";
|
|
27
|
+
import { fileURLToPath } from "url";
|
|
28
|
+
import { getSanityClient } from "../sanity/client.js";
|
|
29
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
30
|
+
const ROOT = resolve(__dirname, "..", "..");
|
|
31
|
+
// Load .env from repository root (same as CLI entry point)
|
|
32
|
+
const envPath = resolve(ROOT, "..", "..", ".env");
|
|
33
|
+
if (existsSync(envPath)) {
|
|
34
|
+
dotenvConfig({ override: true, path: envPath });
|
|
35
|
+
}
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Configuration
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
const DRY_RUN = process.argv.includes("--dry-run");
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Main
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
async function main() {
|
|
44
|
+
console.log("╭──────────────────────────────────────────────╮");
|
|
45
|
+
console.log('│ Phase 7f: Migrate task mode → "literacy" │');
|
|
46
|
+
console.log("╰──────────────────────────────────────────────╯");
|
|
47
|
+
console.log();
|
|
48
|
+
if (DRY_RUN) {
|
|
49
|
+
console.log(" 🏷️ DRY RUN — no documents will be modified.\n");
|
|
50
|
+
}
|
|
51
|
+
const client = getSanityClient({
|
|
52
|
+
token: process.env.AILF_REPORT_SANITY_API_TOKEN || process.env.SANITY_API_TOKEN,
|
|
53
|
+
});
|
|
54
|
+
// Step 1: Find all ailf.task documents without an explicit mode
|
|
55
|
+
const query = `*[_type == "ailf.task" && !defined(mode)]{ _id, title }`;
|
|
56
|
+
const tasksWithoutMode = await client.fetch(query);
|
|
57
|
+
console.log(` Found ${tasksWithoutMode.length} task(s) without an explicit mode.\n`);
|
|
58
|
+
if (tasksWithoutMode.length === 0) {
|
|
59
|
+
console.log(" ✅ Nothing to migrate — all tasks already have a mode.");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// Step 2: Show what would be patched
|
|
63
|
+
for (const task of tasksWithoutMode) {
|
|
64
|
+
const label = task.title ?? task._id;
|
|
65
|
+
console.log(` • ${label} (${task._id})`);
|
|
66
|
+
}
|
|
67
|
+
console.log();
|
|
68
|
+
if (DRY_RUN) {
|
|
69
|
+
console.log(` Would patch ${tasksWithoutMode.length} document(s) with mode: "literacy".`);
|
|
70
|
+
console.log(" Re-run without --dry-run to apply.\n");
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
// Step 3: Patch all matching documents in a transaction
|
|
74
|
+
const transaction = client.transaction();
|
|
75
|
+
for (const task of tasksWithoutMode) {
|
|
76
|
+
transaction.patch(task._id, (patch) => patch.set({ mode: "literacy" }));
|
|
77
|
+
}
|
|
78
|
+
const result = await transaction.commit();
|
|
79
|
+
console.log(` ✅ Patched ${tasksWithoutMode.length} document(s) with mode: "literacy".`);
|
|
80
|
+
console.log(` Transaction ID: ${result.transactionId}\n`);
|
|
81
|
+
}
|
|
82
|
+
main().catch((err) => {
|
|
83
|
+
console.error("Migration failed:", err);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
});
|
|
@@ -138,12 +138,12 @@ function buildReferenceSolutionDoc(task, code, language) {
|
|
|
138
138
|
_type: "ailf.referenceSolution",
|
|
139
139
|
content: sourceToPortableText(code, language),
|
|
140
140
|
language,
|
|
141
|
-
title: `${task.
|
|
141
|
+
title: `${task.title} — Reference Solution`,
|
|
142
142
|
};
|
|
143
143
|
}
|
|
144
144
|
function buildTaskDoc(task, slugToDocId, hasReferenceSolution) {
|
|
145
145
|
// Build canonical docs array with resolved references (slug refs only)
|
|
146
|
-
const canonicalDocs = task.
|
|
146
|
+
const canonicalDocs = (task.context?.docs ?? []).map((ref) => {
|
|
147
147
|
const resolvedId = isSlugRef(ref) ? slugToDocId.get(ref.slug) : undefined;
|
|
148
148
|
return {
|
|
149
149
|
_key: ptKey(),
|
|
@@ -152,7 +152,7 @@ function buildTaskDoc(task, slugToDocId, hasReferenceSolution) {
|
|
|
152
152
|
};
|
|
153
153
|
});
|
|
154
154
|
// Build assertions array
|
|
155
|
-
const assertArray = task.assertions.map((a) => {
|
|
155
|
+
const assertArray = (task.assertions ?? []).map((a) => {
|
|
156
156
|
const entry = {
|
|
157
157
|
_key: ptKey(),
|
|
158
158
|
type: a.type,
|
|
@@ -176,19 +176,20 @@ function buildTaskDoc(task, slugToDocId, hasReferenceSolution) {
|
|
|
176
176
|
}
|
|
177
177
|
return entry;
|
|
178
178
|
});
|
|
179
|
+
const area = task.area ?? "";
|
|
179
180
|
const doc = {
|
|
180
181
|
_id: taskDocId(task.id),
|
|
181
182
|
_type: "ailf.task",
|
|
182
183
|
assert: assertArray,
|
|
183
184
|
canonicalDocs,
|
|
184
|
-
description: task.
|
|
185
|
-
docCoverage: task.docCoverage,
|
|
185
|
+
description: task.title,
|
|
186
|
+
docCoverage: task.docCoverage ?? false,
|
|
186
187
|
featureArea: {
|
|
187
|
-
_ref: featureAreaDocId(
|
|
188
|
+
_ref: featureAreaDocId(area),
|
|
188
189
|
_type: "reference",
|
|
189
190
|
},
|
|
190
191
|
id: { _type: "slug", current: task.id },
|
|
191
|
-
taskPrompt: task.
|
|
192
|
+
taskPrompt: task.prompt?.text ?? "",
|
|
192
193
|
};
|
|
193
194
|
// Optional reference solution
|
|
194
195
|
if (hasReferenceSolution) {
|
|
@@ -220,14 +221,14 @@ async function migrate() {
|
|
|
220
221
|
// 1. Load all tasks from YAML
|
|
221
222
|
console.log("\n1️⃣ Loading tasks from YAML...");
|
|
222
223
|
const taskSource = new YamlTaskSource(ROOT);
|
|
223
|
-
const tasks = await taskSource.loadTasks();
|
|
224
|
+
const tasks = (await taskSource.loadTasks()).filter((t) => t.mode === "literacy");
|
|
224
225
|
console.log(` Loaded ${tasks.length} tasks`);
|
|
225
226
|
// 2. Extract unique feature areas
|
|
226
|
-
const areas = [...new Set(tasks.map((t) => t.
|
|
227
|
+
const areas = [...new Set(tasks.map((t) => t.area ?? ""))].sort();
|
|
227
228
|
console.log(` Found ${areas.length} feature areas: ${areas.join(", ")}`);
|
|
228
229
|
// 3. Collect all canonical doc slugs for batch resolution (slug refs only)
|
|
229
230
|
const allSlugs = [
|
|
230
|
-
...new Set(tasks.flatMap((t) => t.
|
|
231
|
+
...new Set(tasks.flatMap((t) => (t.context?.docs ?? []).filter(isSlugRef).map((d) => d.slug))),
|
|
231
232
|
];
|
|
232
233
|
console.log(` Found ${allSlugs.length} unique canonical doc slugs`);
|
|
233
234
|
// 4. Create Sanity client with write token
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Validation script: Compare YamlTaskSource vs ContentLakeTaskSource
|
|
4
4
|
*
|
|
5
5
|
* Loads tasks from both sources and compares them field-by-field to verify
|
|
6
|
-
* that the Content Lake migration produced identical
|
|
6
|
+
* that the Content Lake migration produced identical LiteracyTaskDefinition[] output.
|
|
7
7
|
*
|
|
8
8
|
* This is Phase 3b of the tasks-as-content exec plan — parallel validation
|
|
9
9
|
* before deleting YAML files.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Validation script: Compare YamlTaskSource vs ContentLakeTaskSource
|
|
4
4
|
*
|
|
5
5
|
* Loads tasks from both sources and compares them field-by-field to verify
|
|
6
|
-
* that the Content Lake migration produced identical
|
|
6
|
+
* that the Content Lake migration produced identical LiteracyTaskDefinition[] output.
|
|
7
7
|
*
|
|
8
8
|
* This is Phase 3b of the tasks-as-content exec plan — parallel validation
|
|
9
9
|
* before deleting YAML files.
|
|
@@ -34,7 +34,7 @@ if (existsSync(envPath)) {
|
|
|
34
34
|
dotenvConfig({ override: true, path: envPath });
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
|
-
* Compare two
|
|
37
|
+
* Compare two LiteracyTaskDefinition arrays field-by-field.
|
|
38
38
|
* Returns a list of differences.
|
|
39
39
|
*/
|
|
40
40
|
function compareTasks(yamlTasks, clTasks) {
|
|
@@ -50,26 +50,26 @@ function compareTasks(yamlTasks, clTasks) {
|
|
|
50
50
|
if (!clTask)
|
|
51
51
|
continue;
|
|
52
52
|
// Compare each field
|
|
53
|
-
compareField(diffs, id, "
|
|
54
|
-
compareField(diffs, id, "
|
|
53
|
+
compareField(diffs, id, "title", yamlTask.title, clTask.title);
|
|
54
|
+
compareField(diffs, id, "area", yamlTask.area, clTask.area);
|
|
55
55
|
compareField(diffs, id, "docCoverage", yamlTask.docCoverage, clTask.docCoverage);
|
|
56
|
-
//
|
|
57
|
-
const yamlPrompt = yamlTask.
|
|
58
|
-
const clPrompt = clTask.
|
|
56
|
+
// prompt.text — normalize whitespace for comparison (YAML multiline vs CL text)
|
|
57
|
+
const yamlPrompt = (yamlTask.prompt?.text ?? "").trim();
|
|
58
|
+
const clPrompt = (clTask.prompt?.text ?? "").trim();
|
|
59
59
|
if (yamlPrompt !== clPrompt) {
|
|
60
60
|
diffs.push({
|
|
61
61
|
clValue: truncate(clPrompt, 100),
|
|
62
|
-
field: "
|
|
62
|
+
field: "prompt.text",
|
|
63
63
|
taskId: id,
|
|
64
64
|
yamlValue: truncate(yamlPrompt, 100),
|
|
65
65
|
});
|
|
66
66
|
}
|
|
67
|
-
//
|
|
68
|
-
const yamlSlugs = yamlTask.
|
|
67
|
+
// context.docs — compare slug sets (slug refs only for comparison)
|
|
68
|
+
const yamlSlugs = (yamlTask.context?.docs ?? [])
|
|
69
69
|
.filter(isSlugRef)
|
|
70
70
|
.map((d) => d.slug)
|
|
71
71
|
.sort();
|
|
72
|
-
const clSlugs = clTask.
|
|
72
|
+
const clSlugs = (clTask.context?.docs ?? [])
|
|
73
73
|
.filter(isSlugRef)
|
|
74
74
|
.map((d) => d.slug)
|
|
75
75
|
.sort();
|
|
@@ -82,7 +82,7 @@ function compareTasks(yamlTasks, clTasks) {
|
|
|
82
82
|
});
|
|
83
83
|
}
|
|
84
84
|
// assertions — compare type + template arrays
|
|
85
|
-
const yamlAssertTypes = yamlTask.assertions
|
|
85
|
+
const yamlAssertTypes = (yamlTask.assertions ?? [])
|
|
86
86
|
.map((a) => {
|
|
87
87
|
const base = a.type;
|
|
88
88
|
if ("template" in a)
|
|
@@ -90,7 +90,7 @@ function compareTasks(yamlTasks, clTasks) {
|
|
|
90
90
|
return base;
|
|
91
91
|
})
|
|
92
92
|
.sort();
|
|
93
|
-
const clAssertTypes = clTask.assertions
|
|
93
|
+
const clAssertTypes = (clTask.assertions ?? [])
|
|
94
94
|
.map((a) => {
|
|
95
95
|
const base = a.type;
|
|
96
96
|
if ("template" in a)
|
|
@@ -130,7 +130,7 @@ async function validate() {
|
|
|
130
130
|
// Load from YAML
|
|
131
131
|
console.log("\n1️⃣ Loading from YAML (tasks/*.yaml)...");
|
|
132
132
|
const yamlSource = new YamlTaskSource(ROOT);
|
|
133
|
-
const yamlTasks = await yamlSource.loadTasks();
|
|
133
|
+
const yamlTasks = (await yamlSource.loadTasks()).filter((t) => t.mode === "literacy");
|
|
134
134
|
console.log(` Loaded ${yamlTasks.length} tasks`);
|
|
135
135
|
// Load from Content Lake (use write token since task docs may require it)
|
|
136
136
|
console.log("\n2️⃣ Loading from Content Lake (ailf.task)...");
|
|
@@ -140,7 +140,7 @@ async function validate() {
|
|
|
140
140
|
undefined,
|
|
141
141
|
});
|
|
142
142
|
const clSource = new ContentLakeTaskSource(client);
|
|
143
|
-
const clTasks = await clSource.loadTasks();
|
|
143
|
+
const clTasks = (await clSource.loadTasks()).filter((t) => t.mode === "literacy");
|
|
144
144
|
console.log(` Loaded ${clTasks.length} tasks`);
|
|
145
145
|
// Compare
|
|
146
146
|
console.log("\n3️⃣ Comparing...");
|
package/dist/sinks/loader.js
CHANGED
|
@@ -7,11 +7,10 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @see docs/design-docs/report-store/sink-architecture.md
|
|
9
9
|
*/
|
|
10
|
-
import { existsSync, readFileSync } from "fs";
|
|
11
10
|
import { dirname, resolve } from "path";
|
|
12
11
|
import { fileURLToPath } from "url";
|
|
13
|
-
import { load } from "js-yaml";
|
|
14
12
|
import { interpolate } from "../interpolate.js";
|
|
13
|
+
import { tryLoadConfigFile } from "../pipeline/compiler/config-loader.js";
|
|
15
14
|
import { BigQuerySink } from "./bigquery/index.js";
|
|
16
15
|
import { SinksFileSchema } from "./schema.js";
|
|
17
16
|
import { SlackSink } from "./slack/index.js";
|
|
@@ -20,7 +19,7 @@ import { WebhookSink } from "./webhook/index.js";
|
|
|
20
19
|
// Paths
|
|
21
20
|
// ---------------------------------------------------------------------------
|
|
22
21
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
23
|
-
const
|
|
22
|
+
const PACKAGE_ROOT = resolve(__dirname, "..", "..");
|
|
24
23
|
// ---------------------------------------------------------------------------
|
|
25
24
|
// Public API
|
|
26
25
|
// ---------------------------------------------------------------------------
|
|
@@ -32,13 +31,12 @@ const SINKS_CONFIG_PATH = resolve(__dirname, "..", "..", "config", "sinks.yaml")
|
|
|
32
31
|
* - The config file fails to parse or validate
|
|
33
32
|
*/
|
|
34
33
|
export function loadSinks() {
|
|
35
|
-
|
|
34
|
+
const loaded = tryLoadConfigFile("sinks", PACKAGE_ROOT);
|
|
35
|
+
if (!loaded) {
|
|
36
36
|
return [];
|
|
37
37
|
}
|
|
38
38
|
try {
|
|
39
|
-
const
|
|
40
|
-
const parsed = load(raw);
|
|
41
|
-
const interpolated = interpolate(parsed);
|
|
39
|
+
const interpolated = interpolate(loaded.data);
|
|
42
40
|
// When all sinks are commented out, js-yaml returns { sinks: null }.
|
|
43
41
|
// Normalize null → undefined so Zod's .default([]) can apply.
|
|
44
42
|
const normalized = interpolated && typeof interpolated === "object"
|