"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateWorkerDecisionSemanticRules = validateWorkerDecisionSemanticRules;
exports.buildWorkerDecisionExample = buildWorkerDecisionExample;
const catalog_1 = require("../i18n/catalog");
const comment_command_1 = require("../workflows/comment-command");
const types_1 = require("../workflows/types");
const constants_1 = require("./constants");
const types_2 = require("./types");
const validation_issues_1 = require("./validation-issues");
const decision_followup_validation_1 = require("./decision-followup-validation");
const decision_step_validation_1 = require("./decision-step-validation");
const workflow_planning_fields_1 = require("./workflow-planning-fields");
const decision_contract_example_text_1 = require("./decision-contract-example-text");
const workflow_selection_fields_1 = require("./workflow-selection-fields");
const workflow_selection_validation_1 = require("./workflow-selection-validation");
function validateWorkerDecisionSemanticRules(decision, workflow, context) {
    const decisionMode = decision.workflow?.mode;
    validateNeedsHumanReason(decision, context);
    validateNeedsHumanReasonWorkflowMode(decision, workflow, context);
    validateContinuationFields(decision, decisionMode, context);
    (0, decision_followup_validation_1.validateFollowupRecommendationFields)(decision, workflow, decisionMode, context);
    validateProceedEvidence(decision, context);
    validateHumanFacingComment(decision, context);
    validateSelectionFields(decision, decisionMode, context);
    validatePlanningOnlyFields(decision, decisionMode, context);
    validateIssueTitleField(decision, context);
    validateWorkflowStartApprovalField(decision, workflow, decisionMode, context);
    validateSelectionProceedRequirements(decision, workflow, decisionMode, context);
    validatePlanningProceedRequirements(decision, workflow, decisionMode, context);
    (0, decision_step_validation_1.validateStepBatchReconciliationRequirements)(decision, workflow, decisionMode, context);
}
function validateNeedsHumanReason(decision, context) {
    if (decision.outcome === constants_1.WORKER_OUTCOMES.waitHuman) {
        if (decision.needsHumanReason === undefined) {
            (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
                path: ["needsHumanReason"],
                message: "needsHumanReason is required when outcome is wait_human.",
            });
        }
        return;
    }
    if (decision.needsHumanReason === undefined) {
        return;
    }
    (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
        path: ["needsHumanReason"],
        message: "needsHumanReason is only allowed when outcome is wait_human.",
    });
}
function validateNeedsHumanReasonWorkflowMode(decision, workflow, context) {
    if (decision.needsHumanReason !== "review_ready") {
        return;
    }
    const effectiveWorkflowMode = decision.workflow?.mode ?? workflow?.mode;
    if (effectiveWorkflowMode !== types_2.WORKER_RUN_MODES.workflowClosing) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["needsHumanReason"],
            message: "needsHumanReason=review_ready is only allowed during workflow_closing.",
        });
        return;
    }
    if (isSourceIssuePullRequestCompletion(workflow)) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["needsHumanReason"],
            message: "needsHumanReason=review_ready is only allowed for human review handoff, not source issue completion that moves to a pull request.",
        });
        return;
    }
}
function isSourceIssuePullRequestCompletion(workflow) {
    return (workflow?.workflowSurface === "issue" &&
        workflow.issueCompletion?.target === "pull_request");
}
function validateContinuationFields(decision, decisionMode, context) {
    if (decision.continuation !== undefined &&
        (decision.outcome !== constants_1.WORKER_OUTCOMES.proceed ||
            (decisionMode !== types_2.WORKER_RUN_MODES.workflowExecute &&
                decisionMode !== types_2.WORKER_RUN_MODES.workflowReconcileStepBatch &&
                decisionMode !== types_2.WORKER_RUN_MODES.workflowClosing))) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["continuation"],
            message: "continuation is only allowed when outcome is proceed and workflow mode is workflow_execute, workflow_reconcile_step_batch, or workflow_closing.",
        });
    }
}
function validateProceedEvidence(decision, context, pathPrefix = []) {
    if (decision.outcome !== constants_1.WORKER_OUTCOMES.proceed) {
        return;
    }
    if (hasNonEmptyResultEvidence(decision.result)) {
        return;
    }
    (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
        path: [...pathPrefix, "result", "evidence"],
        message: "proceed decisions must include non-empty completion evidence in result.evidence.",
    });
}
function validateHumanFacingComment(decision, context, pathPrefix = []) {
    if (decision.outcome === constants_1.WORKER_OUTCOMES.proceed) {
        return;
    }
    if (hasNonEmptyText(decision.result.humanComment)) {
        return;
    }
    (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
        path: [...pathPrefix, "result", "humanComment"],
        message: "wait_human and fail decisions must include the human-facing reason in result.humanComment.",
    });
}
function validateStepResult(step, context, pathPrefix) {
    if (step.result === null || step.result === undefined) {
        return;
    }
    const resultDecision = {
        outcome: step.result.outcome,
        result: (0, types_1.buildWorkflowResultFieldsWithDefaults)(step.result),
    };
    validateProceedEvidence(resultDecision, context, pathPrefix);
    validateHumanFacingComment(resultDecision, context, pathPrefix);
}
function hasNonEmptyResultEvidence(result) {
    return result.evidence.some((entry) => hasNonEmptyText(entry));
}
function hasNonEmptyText(value) {
    return value !== undefined && value !== null && value.trim().length > 0;
}
function validateSelectionFields(decision, decisionMode, context) {
    if (decision.selection !== undefined &&
        decisionMode !== types_2.WORKER_RUN_MODES.workflowSelect) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["selection"],
            message: "selection is only allowed when workflow mode is workflow_select.",
        });
        return;
    }
    if (decisionMode !== types_2.WORKER_RUN_MODES.workflowSelect ||
        decision.outcome !== constants_1.WORKER_OUTCOMES.proceed) {
        return;
    }
    if (decision.selection === undefined || decision.selection === null) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["selection"],
            message: "selection is required when workflow mode is workflow_select and outcome is proceed.",
        });
    }
}
function validatePlanningOnlyFields(decision, decisionMode, context) {
    for (const field of workflow_planning_fields_1.WORKFLOW_PLANNING_ONLY_FIELD_NAMES) {
        if (decision[field] !== undefined &&
            decisionMode !== types_2.WORKER_RUN_MODES.workflowPlan) {
            (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
                path: [field],
                message: `${field} is only allowed when workflow mode is workflow_plan.`,
            });
        }
    }
}
function validatePlanningProceedRequirements(decision, workflow, decisionMode, context) {
    if (decisionMode !== types_2.WORKER_RUN_MODES.workflowPlan ||
        decision.outcome !== constants_1.WORKER_OUTCOMES.proceed) {
        return;
    }
    const requiredFields = (0, workflow_planning_fields_1.getWorkflowPlanningRequiredProceedFieldNames)(workflow);
    for (const field of requiredFields) {
        if (decision[field] === undefined || decision[field] === null) {
            (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
                path: [field],
                message: `${field} is required when workflow mode is workflow_plan and outcome is proceed.`,
            });
        }
    }
    if ((workflow?.planningIntent === "replan" ||
        workflow?.planningIntent === "revise_plan") &&
        decision.plan !== undefined) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["plan"],
            message: "plan must be omitted for replan and revise_plan; use planPatch instead.",
        });
    }
    if (workflow?.planningIntent !== "replan" &&
        workflow?.planningIntent !== "revise_plan" &&
        decision.planPatch !== undefined) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["planPatch"],
            message: "planPatch is only allowed for replan and revise_plan.",
        });
    }
    if ((0, workflow_planning_fields_1.isAdaptiveWorkflowStartApprovalMode)(workflow?.startApprovalMode) &&
        decision.workflowStartApproval === undefined) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["workflowStartApproval"],
            message: "workflowStartApproval is required when workflow mode is workflow_plan, outcome is proceed, and workflow.startApprovalMode is conservative or aggressive.",
        });
    }
    validateUniqueChildIssueStepKeys(decision, context);
    validateWorkflowPlanSteps(decision, workflow, context);
    validateWorkflowPlanPatch(decision, workflow, context);
}
function validateIssueTitleField(decision, context) {
    const issueTitle = decision.issueTitle?.trim() ?? null;
    if (issueTitle === null) {
        return;
    }
    if (issueTitle.startsWith("[recurring]") ||
        issueTitle.startsWith("[定期]") ||
        issueTitle.startsWith("[定时]")) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["issueTitle"],
            message: "issueTitle must contain only the central work name, without recurring title prefixes.",
        });
    }
    if (/(^|\s)\(#[^()]+\)(?=\s|$)/u.test(issueTitle)) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["issueTitle"],
            message: "issueTitle must contain only the central work name, without a parent issue suffix.",
        });
    }
    if ((0, comment_command_1.hasIssueCommentCommandOnFirstNonEmptyLine)(issueTitle)) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["issueTitle"],
            message: "issueTitle must not start with /alpaca command text.",
        });
    }
}
function validateWorkflowStartApprovalField(decision, workflow, decisionMode, context) {
    if (decision.workflowStartApproval === undefined) {
        return;
    }
    if (decisionMode !== types_2.WORKER_RUN_MODES.workflowPlan ||
        decision.outcome !== constants_1.WORKER_OUTCOMES.proceed) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["workflowStartApproval"],
            message: "workflowStartApproval is only allowed when workflow mode is workflow_plan and outcome is proceed.",
        });
        return;
    }
    if (!(0, workflow_planning_fields_1.isAdaptiveWorkflowStartApprovalMode)(workflow?.startApprovalMode)) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["workflowStartApproval"],
            message: "workflowStartApproval is only allowed when workflow.startApprovalMode is conservative or aggressive.",
        });
    }
}
function validateExplicitSelectionLock(selection, selectionContext, context, input) {
    const explicitValue = (0, workflow_selection_fields_1.getActiveWorkflowSelectionExplicitTemplateName)(selectionContext);
    if (explicitValue === undefined) {
        return;
    }
    const action = (0, workflow_selection_fields_1.getActiveWorkflowSelectionAction)(selection);
    const templateName = (0, workflow_selection_fields_1.getActiveWorkflowSelectionTemplateName)(selection);
    if ((explicitValue === null &&
        action === types_2.WORKER_WORKFLOW_SELECTION_ACTIONS.noTemplate) ||
        (explicitValue !== null &&
            action === types_2.WORKER_WORKFLOW_SELECTION_ACTIONS.useTemplate &&
            templateName === explicitValue)) {
        return;
    }
    const path = explicitValue === null
        ? ["selection", input.actionFieldName]
        : ["selection", input.templateFieldName];
    (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
        path,
        message: `selection must preserve ${formatSelectionValueForMessage(explicitValue)} when workflow.selection.${input.contextFieldName} is provided.`,
    });
}
function formatSelectionValueForMessage(value) {
    return value === null ? "null" : value;
}
function validateSelectionProceedRequirements(decision, workflow, decisionMode, context) {
    if (decisionMode !== types_2.WORKER_RUN_MODES.workflowSelect ||
        decision.outcome !== constants_1.WORKER_OUTCOMES.proceed) {
        return;
    }
    const selection = decision.selection;
    if (selection === undefined || selection === null) {
        return;
    }
    const selectionContext = workflow?.selection ?? null;
    for (const spec of workflow_selection_fields_1.ACTIVE_WORKFLOW_SELECTION_FIELD_SPECS) {
        validateExplicitSelectionLock(selection, selectionContext, context, {
            actionFieldName: spec.actionField,
            templateFieldName: spec.selectionField,
            contextFieldName: spec.explicitField,
        });
        addWorkflowSelectionFieldAnalysisIssues(selection, selectionContext, context, spec);
    }
}
function addWorkflowSelectionFieldAnalysisIssues(selection, selectionContext, context, spec) {
    const analysis = (0, workflow_selection_validation_1.analyzeWorkflowSelectionField)({
        spec,
        action: (0, workflow_selection_fields_1.getActiveWorkflowSelectionAction)(selection),
        value: (0, workflow_selection_fields_1.getActiveWorkflowSelectionTemplateName)(selection),
        explicitTemplateName: (0, workflow_selection_fields_1.getActiveWorkflowSelectionExplicitTemplateName)(selectionContext),
        slotMode: (0, workflow_selection_fields_1.getActiveWorkflowSelectionSlotMode)(selectionContext),
        candidates: (0, workflow_selection_fields_1.getActiveWorkflowSelectionCandidates)(selectionContext),
        candidateSetProvided: (0, workflow_selection_fields_1.getActiveWorkflowSelectionCandidates)(selectionContext) !== undefined,
        skipCandidateValidationForExplicitSelection: true,
    });
    if (analysis.autoActionMissing) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["selection", spec.actionField],
            message: `selection.${spec.actionField} is required when workflow.selection.${spec.slotField} is auto or auto_select.`,
        });
    }
    if (analysis.useTemplateNameMissing) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["selection", spec.selectionField],
            message: "selection.templateName is required when action is use_template.",
        });
    }
    if (analysis.candidateIssue === "invalid-candidate") {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["selection", spec.selectionField],
            message: spec.invalidCandidateMessage,
        });
    }
    if (analysis.candidateIssue === "empty-candidates") {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["selection", spec.selectionField],
            message: spec.invalidCandidateMessage,
        });
    }
    const action = (0, workflow_selection_fields_1.getActiveWorkflowSelectionAction)(selection);
    const slotMode = (0, workflow_selection_fields_1.getActiveWorkflowSelectionSlotMode)(selectionContext);
    const explicitTemplateName = (0, workflow_selection_fields_1.getActiveWorkflowSelectionExplicitTemplateName)(selectionContext);
    if (action === types_2.WORKER_WORKFLOW_SELECTION_ACTIONS.requestTemplate &&
        slotMode !== "auto" &&
        explicitTemplateName === undefined) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["selection", spec.actionField],
            message: "request_template selection requires an auto slot.",
        });
    }
    if (action === types_2.WORKER_WORKFLOW_SELECTION_ACTIONS.noTemplate &&
        slotMode !== "auto" &&
        slotMode !== "auto_select" &&
        explicitTemplateName === undefined) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["selection", spec.actionField],
            message: "no_template selection requires an auto/auto_select slot or explicit no_template lock.",
        });
    }
}
function buildWorkerDecisionExample(workflow, outputLanguage = catalog_1.DEFAULT_APP_LOCALE) {
    const text = (0, decision_contract_example_text_1.getWorkerDecisionExampleText)(outputLanguage);
    const contract = {
        outcome: constants_1.WORKER_OUTCOMES.proceed,
        result: {
            resultSummary: text.resultSummary,
            evidence: text.evidence,
            humanComment: null,
        },
    };
    if (!workflow) {
        return contract;
    }
    contract.workflow = {
        mode: workflow.mode,
        templateName: workflow.templateName,
    };
    if (workflow.mode === types_2.WORKER_RUN_MODES.workflowExecute) {
        contract.result = {
            resultSummary: text.executionResultSummary,
            evidence: text.executionEvidence,
            humanComment: null,
        };
        contract.commitMessage = null;
        return contract;
    }
    if (workflow.mode === types_2.WORKER_RUN_MODES.workflowReconcileStepBatch) {
        const batchSteps = workflow.stepBatchReconciliation?.steps ?? [
            { id: "step-a" },
            { id: "step-b" },
        ];
        contract.result = {
            resultSummary: text.batchResultSummary,
            evidence: text.batchEvidence,
            humanComment: null,
        };
        contract.stepResults = batchSteps.map((step) => ({
            stepId: step.id,
            outcome: constants_1.WORKER_OUTCOMES.proceed,
            result: {
                resultSummary: text.stepResultSummary,
                evidence: text.stepEvidence,
                humanComment: null,
            },
        }));
        contract.commitMessage = null;
        return contract;
    }
    if (workflow.mode === types_2.WORKER_RUN_MODES.workflowClosing) {
        contract.result = {
            resultSummary: text.executionResultSummary,
            evidence: text.executionEvidence,
            humanComment: null,
        };
        contract.commitMessage = null;
        if (workflow.state?.followup?.proposalPolicy !== "off") {
            contract.followupRecommendation = {
                recommended: false,
                reason: "No independent post-completion follow-up is needed.",
                items: [],
            };
        }
        return contract;
    }
    if (workflow.mode === types_2.WORKER_RUN_MODES.workflowSelect) {
        const selectionContext = workflow.selection ?? null;
        contract.result = {
            resultSummary: text.selectionResultSummary,
            evidence: text.selectionEvidence,
            humanComment: null,
        };
        contract.selection = buildExampleSelectionFields(selectionContext);
        return contract;
    }
    contract.contract = {
        objective: text.contractObjective,
        doneWhen: text.contractDoneWhen,
        inputs: text.contractInputs,
        outputs: text.contractOutputs,
    };
    contract.result = {
        resultSummary: text.planningResultSummary,
        evidence: text.planningEvidence,
        humanComment: null,
    };
    if (workflow.planningIntent === "replan" ||
        workflow.planningIntent === "revise_plan") {
        contract.planPatch = {
            basePlanRevision: workflow.state?.planRevision ?? 0,
            intent: workflow.planningIntent,
            summary: text.planningResultSummary,
            scope: {
                issueRef: "#123",
            },
            stepChanges: [],
            childIssueDecisions: [],
            workflowRefChanges: [],
        };
    }
    else {
        contract.issueTitle = text.planningIssueTitle;
        contract.priorityRank = 2000;
        contract.plan = {
            steps: buildWorkerPlanExampleSteps(workflow, text),
        };
        contract.executionGuidance = text.executionGuidance;
        contract.predictedTouchedPaths = [
            ...workflow_planning_fields_1.WORKFLOW_PLANNING_EXAMPLE_FIELDS.predictedTouchedPaths,
        ];
    }
    if ((0, workflow_planning_fields_1.isAdaptiveWorkflowStartApprovalMode)(workflow.startApprovalMode)) {
        contract.workflowStartApproval = {
            required: true,
            reason: text.startApprovalReason,
        };
    }
    return contract;
}
function buildExampleSelectionFields(selectionContext) {
    const selection = {};
    for (const spec of workflow_selection_fields_1.ACTIVE_WORKFLOW_SELECTION_FIELD_SPECS) {
        const selected = buildExampleSelection({
            spec,
            explicitTemplateName: (0, workflow_selection_fields_1.getActiveWorkflowSelectionExplicitTemplateName)(selectionContext),
            slotMode: (0, workflow_selection_fields_1.getActiveWorkflowSelectionSlotMode)(selectionContext),
            candidates: (0, workflow_selection_fields_1.getActiveWorkflowSelectionCandidates)(selectionContext),
        });
        if (selected.include) {
            selection.action = selected.action;
            if (selected.templateName !== undefined) {
                selection.templateName = selected.templateName;
            }
        }
    }
    return (0, workflow_selection_fields_1.buildActiveWorkflowSelectionDecision)(selection);
}
function buildExampleSelection(input) {
    if (input.explicitTemplateName !== undefined) {
        return input.explicitTemplateName === null
            ? { include: true, action: types_2.WORKER_WORKFLOW_SELECTION_ACTIONS.noTemplate }
            : {
                include: true,
                action: types_2.WORKER_WORKFLOW_SELECTION_ACTIONS.useTemplate,
                templateName: input.explicitTemplateName,
            };
    }
    if (input.slotMode === "auto" || input.slotMode === "auto_select") {
        const firstCandidate = input.candidates?.[0]?.templateName;
        return firstCandidate === undefined
            ? { include: true, action: types_2.WORKER_WORKFLOW_SELECTION_ACTIONS.noTemplate }
            : {
                include: true,
                action: types_2.WORKER_WORKFLOW_SELECTION_ACTIONS.useTemplate,
                templateName: firstCandidate,
            };
    }
    return { include: false };
}
function buildWorkerPlanExampleSteps(workflow, text) {
    const directChildWorkflows = workflow.directChildWorkflows ?? [];
    if (directChildWorkflows.length === 0) {
        return [
            {
                id: "plan-template-work",
                kind: "task",
                title: text.taskStep.title,
                objective: text.taskStep.objective,
                instructions: text.taskStep.instructions,
                doneWhen: text.taskStep.doneWhen,
                humanHandoffWhen: [],
                dependsOnStepIds: [],
                result: null,
            },
        ];
    }
    return directChildWorkflows.map((entry, index) => ({
        id: `expand-${index + 1}`,
        kind: "workflow_ref",
        title: text.workflowRef.title(entry.templateName),
        objective: text.workflowRef.objective(entry.templateName),
        instructions: text.workflowRef.instructions(entry.templateName),
        doneWhen: text.workflowRef.doneWhen(entry.templateName),
        humanHandoffWhen: text.workflowRef.humanHandoffWhen(entry.templateName),
        dependsOnStepIds: [],
        targetTemplateName: entry.templateName,
        callSiteId: entry.callSiteId,
        sourceTemplateName: workflow.templateName ?? "template",
        sourceTemplateDigest: "digest",
        expansionGroupId: entry.callSiteId,
        result: null,
    }));
}
function validateWorkflowPlanSteps(decision, workflow, context) {
    if (workflow?.mode !== types_2.WORKER_RUN_MODES.workflowPlan ||
        decision.plan === undefined ||
        decision.plan === null) {
        return;
    }
    const directChildWorkflows = workflow.directChildWorkflows ?? [];
    const workflowPlan = decision.plan;
    (0, decision_step_validation_1.validateWorkflowPlanStepGraph)(decision, workflow, context);
    workflowPlan.steps.forEach((step, index) => {
        validateStepResult(step, context, ["plan", "steps", index]);
    });
    const expectedCallSiteIds = directChildWorkflows.map((entry) => entry.callSiteId);
    const actualWorkflowRefs = workflowPlan.steps.flatMap((step, index) => step.kind === "workflow_ref"
        ? [
            {
                index,
                callSiteId: step.callSiteId,
                targetTemplateName: step.targetTemplateName,
            },
        ]
        : []);
    for (const [expectedIndex, entry] of directChildWorkflows.entries()) {
        const matches = actualWorkflowRefs.filter((step) => step.callSiteId === entry.callSiteId);
        if (matches.length !== 1) {
            (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
                path: ["plan", "steps"],
                message: `Direct child workflow call site ${entry.callSiteId} must appear exactly once as workflow_ref.`,
            });
            continue;
        }
        const match = matches[0];
        if (match === undefined) {
            continue;
        }
        if (match.targetTemplateName !== entry.templateName) {
            (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
                path: ["plan", "steps", match.index, "targetTemplateName"],
                message: `workflow_ref ${entry.callSiteId} must target ${entry.templateName}.`,
            });
        }
        const previousEntry = directChildWorkflows[expectedIndex - 1];
        const previousMatch = previousEntry === undefined
            ? undefined
            : actualWorkflowRefs.find((step) => step.callSiteId === previousEntry.callSiteId);
        if (previousMatch !== undefined && match.index < previousMatch.index) {
            (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
                path: ["plan", "steps"],
                message: "workflow_ref steps must preserve direct child call-site order.",
            });
        }
    }
    for (const workflowRef of actualWorkflowRefs) {
        if (!expectedCallSiteIds.includes(workflowRef.callSiteId)) {
            (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
                path: ["plan", "steps", workflowRef.index, "callSiteId"],
                message: "workflow_ref steps may only reference direct child workflow call sites from the active template.",
            });
        }
    }
}
function validateWorkflowPlanPatch(decision, workflow, context) {
    if (workflow?.mode !== types_2.WORKER_RUN_MODES.workflowPlan ||
        decision.planPatch === undefined ||
        decision.planPatch === null) {
        return;
    }
    if (decision.planPatch.intent !== workflow.planningIntent) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
            path: ["planPatch", "intent"],
            message: "planPatch.intent must match workflow.planningIntent.",
        });
    }
    if (workflow.state !== null) {
        const expectedBasePlanRevision = workflow.state.planRevision;
        const receivedBasePlanRevision = decision.planPatch.basePlanRevision;
        if (receivedBasePlanRevision !== expectedBasePlanRevision) {
            (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
                path: ["planPatch", "basePlanRevision"],
                message: `planPatch.basePlanRevision must equal the current workflow state planRevision ${expectedBasePlanRevision}; received ${receivedBasePlanRevision}. Do not use workflow state version ${workflow.state.version}.`,
            });
        }
    }
    const planStepById = new Map((workflow.state?.plan?.steps ?? []).map((step) => [step.id, step]));
    const directChildWorkflowByCallSiteId = new Map((workflow.directChildWorkflows ?? []).map((entry) => [entry.callSiteId, entry]));
    decision.planPatch.stepChanges.forEach((change, index) => {
        if ((change.action === "add_step" || change.action === "update_step") &&
            change.step.result !== undefined &&
            change.step.result !== null) {
            (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
                path: ["planPatch", "stepChanges", index, "step", "result"],
                message: "planPatch step changes must not include completed step results.",
            });
        }
        if (change.action === "update_step" && change.step.id !== change.stepId) {
            (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
                path: ["planPatch", "stepChanges", index, "step", "id"],
                message: "update_step must keep step.id equal to stepId.",
            });
        }
        if (change.action === "move_step") {
            validateWorkflowPlanPatchMoveStep({
                change,
                index,
                planStepById,
                context,
            });
        }
        if (change.action === "add_step" || change.action === "update_step") {
            validateWorkflowPlanPatchStepMetadata({
                step: change.step,
                directChildWorkflowByCallSiteId,
                context,
                path: ["planPatch", "stepChanges", index, "step"],
            });
        }
    });
}
function validateWorkflowPlanPatchMoveStep(input) {
    const path = ["planPatch", "stepChanges", input.index];
    const target = input.planStepById.get(input.change.stepId);
    if (target === undefined) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(input.context, {
            path: [...path, "stepId"],
            message: `move_step target ${input.change.stepId} must exist in the current plan.`,
        });
    }
    else {
        validateWorkflowPlanPatchMoveStepTarget({
            target,
            path,
            context: input.context,
        });
    }
    const afterStepId = input.change.afterStepId ?? null;
    if (afterStepId === null) {
        return;
    }
    if (afterStepId === input.change.stepId) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(input.context, {
            path: [...path, "afterStepId"],
            message: "move_step cannot move a step after itself.",
        });
        return;
    }
    if (!input.planStepById.has(afterStepId)) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(input.context, {
            path: [...path, "afterStepId"],
            message: `move_step afterStepId ${afterStepId} must exist in the current plan.`,
        });
    }
}
function validateWorkflowPlanPatchMoveStepTarget(input) {
    if (input.target.result !== null) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(input.context, {
            path: [...input.path, "stepId"],
            message: "move_step can only move incomplete steps.",
        });
    }
    if (input.target.kind === "workflow_ref") {
        (0, validation_issues_1.addWorkerZodValidationIssue)(input.context, {
            path: [...input.path, "stepId"],
            message: "move_step cannot move workflow_ref steps; use workflowRefChanges for reusable workflow placement.",
        });
    }
    else if (input.target.kind !== "task" &&
        !(0, types_1.isWorkflowChildIssueStep)(input.target)) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(input.context, {
            path: [...input.path, "stepId"],
            message: "move_step can only target task or unmaterialized child_issue steps.",
        });
    }
    if (input.target.originSubtreeKey !== undefined ||
        input.target.originWorkflowRef !== undefined) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(input.context, {
            path: [...input.path, "stepId"],
            message: "move_step cannot move expanded workflow_ref subtree steps; use workflowRefChanges instead.",
        });
    }
    if ((0, types_1.isWorkflowChildIssueStep)(input.target) &&
        input.target.childIssueRef !== null) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(input.context, {
            path: [...input.path, "stepId"],
            message: "move_step can only move child_issue steps before they are materialized.",
        });
    }
}
function validateWorkflowPlanPatchStepMetadata(input) {
    if (input.step.kind !== "workflow_ref") {
        return;
    }
    const expected = input.directChildWorkflowByCallSiteId.get(input.step.callSiteId);
    if (expected === undefined) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(input.context, {
            path: [...input.path, "callSiteId"],
            message: "planPatch workflow_ref steps may only reference direct child workflow call sites from the active template.",
        });
        return;
    }
    if (input.step.targetTemplateName !== expected.templateName) {
        (0, validation_issues_1.addWorkerZodValidationIssue)(input.context, {
            path: [...input.path, "targetTemplateName"],
            message: `workflow_ref ${expected.callSiteId} must target ${expected.templateName}.`,
        });
    }
}
function validateUniqueChildIssueStepKeys(decision, context) {
    if (decision.plan === undefined || decision.plan === null) {
        return;
    }
    const seenChildKeys = new Set();
    decision.plan.steps.forEach((step, index) => {
        if (step.kind !== "child_issue") {
            return;
        }
        if (seenChildKeys.has(step.childKey)) {
            (0, validation_issues_1.addWorkerZodValidationIssue)(context, {
                path: ["plan", "steps", index, "childKey"],
                message: "childKey must be unique within child_issue plan steps.",
            });
        }
        seenChildKeys.add(step.childKey);
    });
}
