/**
 * repo-validation.ts — Semantic validation for task definitions.
 *
 * Checks that go beyond Zod schema parsing:
 * - Assertion types are in the curated set
 * - Rubric template names resolve to known templates
 * - Doc ref slugs look reasonable (slugs, not URLs)
 * - Tasks have at least one LLM rubric assertion (recommended)
 * - Tasks have a prompt text (recommended)
 *
 * These produce warnings, not errors — the pipeline can still run
 * with imperfect tasks. Only structural failures (caught by Zod) block.
 *
 * Previously this file re-exported from @sanity/ailf-tasks. That package
 * has been eliminated — all validation logic now lives here.
 */
import { CURATED_ASSERTION_TYPES, RUBRIC_TEMPLATE_NAMES, } from "./repo-schemas.js";
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
/**
 * Run semantic validation on an array of parsed canonical tasks.
 *
 * Returns warnings for issues that don't block execution (unknown feature
 * areas, unresolved slugs) and errors for issues that would cause pipeline
 * failures (completely missing required fields — though Zod catches most).
 */
export function validateCanonicalTasks(tasks) {
    const errors = [];
    const warnings = [];
    // Check for duplicate IDs
    const seenIds = new Set();
    for (const task of tasks) {
        if (seenIds.has(task.id)) {
            errors.push({
                taskId: task.id,
                field: "id",
                message: `Duplicate task ID "${task.id}"`,
            });
        }
        seenIds.add(task.id);
    }
    for (const task of tasks) {
        const assertions = task.assertions ?? [];
        // Check assertion types
        for (let i = 0; i < assertions.length; i++) {
            const assertion = assertions[i];
            if (!CURATED_ASSERTION_TYPES.includes(assertion.type)) {
                warnings.push({
                    taskId: task.id,
                    field: `assertions[${i}].type`,
                    message: `Unknown assertion type "${assertion.type}". ` +
                        `Valid types: ${CURATED_ASSERTION_TYPES.join(", ")}`,
                });
            }
            // Check rubric template for llm-rubric assertions
            if (assertion.type === "llm-rubric" && "template" in assertion) {
                const template = assertion.template;
                if (!RUBRIC_TEMPLATE_NAMES.includes(template)) {
                    warnings.push({
                        taskId: task.id,
                        field: `assertions[${i}].template`,
                        message: `Unknown rubric template "${template}". ` +
                            `Valid templates: ${RUBRIC_TEMPLATE_NAMES.join(", ")}`,
                    });
                }
            }
        }
        // Check canonical doc refs look reasonable
        const docs = task.context?.docs ?? [];
        for (let i = 0; i < docs.length; i++) {
            const doc = docs[i];
            // Slug refs: warn if they look like URLs or paths
            if ("slug" in doc && !("id" in doc) && typeof doc.slug === "string") {
                if (doc.slug.includes("/") || doc.slug.includes("http")) {
                    warnings.push({
                        taskId: task.id,
                        field: `context.docs[${i}].slug`,
                        message: `Slug "${doc.slug}" looks like a URL or path — use 'path' type for paths or 'slug' for document slugs (e.g., "groq-introduction")`,
                    });
                }
            }
        }
        // Check task has at least one llm-rubric assertion (recommended but not required).
        // agent-harness tasks grade side-effects (file-exists, command-succeeds, etc.),
        // not text output, so an llm-rubric is not expected.
        const hasLlmRubric = assertions.some((a) => a.type === "llm-rubric");
        if (!hasLlmRubric && task.mode !== "agent-harness") {
            warnings.push({
                taskId: task.id,
                field: "assertions",
                message: "No llm-rubric assertion found. Tasks should have at least one scored rubric for meaningful evaluation.",
            });
        }
        // Check prompt text exists
        if (!task.prompt?.text) {
            warnings.push({
                taskId: task.id,
                field: "prompt.text",
                message: "No task prompt found in prompt.text. The LLM will receive an empty implementation request.",
            });
        }
    }
    return {
        valid: errors.length === 0,
        errors,
        warnings,
    };
}
/**
 * Format validation results for console output.
 */
export function formatRepoValidationResult(result) {
    const lines = [];
    if (result.errors.length > 0) {
        lines.push("Errors:");
        for (const e of result.errors) {
            lines.push(`  [${e.taskId}] ${e.field}: ${e.message}`);
        }
    }
    if (result.warnings.length > 0) {
        lines.push("Warnings:");
        for (const w of result.warnings) {
            lines.push(`  [${w.taskId}] ${w.field}: ${w.message}`);
        }
    }
    if (result.valid && result.warnings.length === 0) {
        lines.push("All tasks pass validation");
    }
    return lines.join("\n");
}
