export const REQUEST_BRIEF_FILE = 'request-brief.json';
export const SELECTION_PLAN_FILE = 'selection-plan.json';
export const CONTEXT_LOG_FILE = 'context-log.jsonl';
export const DECISION_LOG_FILE = 'decision-log.jsonl';
function short(value, limit = 280) {
    const text = String(value ?? '').replace(/\s+/g, ' ').trim();
    return text.length > limit ? `${text.slice(0, Math.max(0, limit - 1))}...` : text;
}
function unique(values, limit = 50) {
    return [...new Set(values.map((value) => String(value ?? '').trim()).filter(Boolean))].slice(0, limit);
}
function actionName(action) {
    return short(action.command ?? action.type ?? action.name ?? action.tool ?? JSON.stringify(action), 160);
}
function diffFiles(diff) {
    const text = String(diff ?? '');
    if (!text.trim())
        return [];
    const files = [];
    for (const line of text.split('\n')) {
        const gitMatch = /^diff --git a\/(.+?) b\/(.+)$/.exec(line);
        if (gitMatch?.[2] && gitMatch[2] !== '/dev/null')
            files.push(gitMatch[2]);
        const plusMatch = /^\+\+\+ b\/(.+)$/.exec(line);
        if (plusMatch?.[1] && plusMatch[1] !== '/dev/null')
            files.push(plusMatch[1]);
    }
    return unique(files, 80);
}
function extractChangedFiles(run) {
    return unique([
        ...(run.changedFiles ?? []),
        ...(run.finalDecision?.changedFiles ?? []),
        ...(run.workerResults ?? []).flatMap((result) => [
            ...(result.modifiedFiles ?? []),
            ...(result.changedFiles ?? []),
            ...(result.filesChanged ?? []),
            ...diffFiles(result.diff),
        ]),
        ...diffFiles(run.finalDecision?.synthesized),
        ...diffFiles(run.finalDecision?.winner?.diff),
    ], 80);
}
export function buildContextRouterSnapshot(run, selected) {
    const actionsBound = Number(selected.actions?.length ?? 0);
    const workersPlanned = Number(selected.workers?.length ?? run.workerManifests?.length ?? 0);
    const workersExecuted = Number(run.workerResults?.length ?? 0);
    const workersVerified = Number((run.verificationResults ?? [])
        .filter((entry) => entry.status === 'passed' || entry.passed).length);
    const changedFiles = unique(selected.changedFiles ?? extractChangedFiles(run), 80);
    const status = changedFiles.length > 0
        ? 'changed'
        : actionsBound > 0
            ? 'dispatched'
            : workersExecuted > 0
                ? 'advisory'
                : 'planned';
    const crew = unique(selected.crews ?? [], 12);
    const specialists = unique(selected.specialists ?? [], 20);
    const reason = status === 'advisory'
        ? 'A crew/specialist route was selected, but no mutation action bindings or changed files were recorded.'
        : status === 'changed'
            ? 'The selected route produced file changes that are attached to this run.'
            : status === 'dispatched'
                ? 'The selected route included executable action bindings.'
                : 'The route was planned and is waiting for executable work.';
    return {
        status,
        selectedCrew: crew,
        specialists,
        workersPlanned,
        workersExecuted,
        workersVerified,
        actionsBound,
        changedFiles,
        verifyCommands: unique(selected.verifyCommands ?? [], 40),
        reason,
    };
}
function normalizeIntent(input) {
    const raw = String(input ?? '').toLowerCase();
    if (raw === 'inspect' || raw === 'plan' || raw === 'mutate')
        return raw;
    if (raw === 'verify' || raw === 'release' || raw === 'operate')
        return raw;
    return 'mutate';
}
function inferArtifactType(intent, task) {
    if (intent === 'plan')
        return 'plan';
    if (intent === 'inspect')
        return 'answer';
    if (intent === 'verify')
        return 'test';
    if (intent === 'release')
        return 'release';
    if (task.manualOverrides?.length || task.actions?.some((action) => action.type === 'run_command')) {
        return 'test';
    }
    return 'patch';
}
function inferRisk(task) {
    const text = [
        task.goal,
        ...(task.files ?? []),
        ...(task.verifyCommands ?? []),
        ...(task.manualOverrides ?? []),
        ...(task.actions ?? []).map(actionName),
    ].join(' ').toLowerCase();
    const intent = normalizeIntent(task.intent);
    const readOnlyIntent = intent === 'inspect' || intent === 'plan';
    const controlPlaneCore = /(orchestrat|synapse|runtime|scheduler|workflow|mcp|model routing|hiring|selection|control plane|worker|dispatch|queue|queued|scheduled)/i.test(text);
    const mutationIntent = /\b(fix|patch|change|modify|implement|build|create|harden|refactor|rewrite|repair|improve)\b/i.test(text);
    if (/(delete|destroy|drop table|rm\s+-rf|force-push|production|credential|secret|billing|payment)/i.test(text)) {
        return 'critical';
    }
    if (!readOnlyIntent && controlPlaneCore && mutationIntent) {
        return 'high';
    }
    if ((task.files ?? []).length > 8 || Number(task.workers ?? 1) > 3 || /(release|migration|auth|security)/i.test(text)) {
        return 'high';
    }
    if (!readOnlyIntent && (mutationIntent || /(bug|broken|not working|doesn.t work|scheduled|queued)/i.test(text))) {
        return 'medium';
    }
    if ((task.files ?? []).length > 0 || (task.actions ?? []).length > 0)
        return 'medium';
    return 'low';
}
export function inferModelRoute(input) {
    const task = input.task ?? {};
    const run = input.run ?? {};
    const risk = input.risk ?? inferRisk(task);
    const confidence = Number(input.confidence ?? 0.76);
    const workerCount = Number(task.workers ?? run.workerResults?.length ?? 1);
    const provider = (tier, selectedClient) => {
        const selectedModel = selectedClient === 'claude'
            ? (tier === 'T4' ? 'Claude Opus 4.8' : 'Claude Sonnet 4.6')
            : selectedClient === 'cursor'
                ? (tier === 'T1' ? 'Cursor Auto' : 'Cursor Max/Auto')
                : (tier === 'T1' ? 'gpt-5.4-mini' : 'gpt-5.5');
        return {
            selectedClient,
            selectedModel,
            contextWindow: tier === 'T1' ? 'cost-first compact context' : 'long-context verified route',
            providerChoices: [
                {
                    client: 'codex',
                    model: tier === 'T1' ? 'gpt-5.4-mini' : 'gpt-5.5',
                    role: 'primary coding, tests, and final integration',
                    contextWindow: tier === 'T1' ? '400K' : '1M',
                    selected: selectedClient === 'codex',
                },
                {
                    client: 'claude',
                    model: tier === 'T4' ? 'Claude Opus 4.8' : 'Claude Sonnet 4.6',
                    role: 'deep planning, Claude Code handoff, and reviewer lane',
                    contextWindow: '1M',
                    selected: selectedClient === 'claude',
                },
                {
                    client: 'cursor',
                    model: tier === 'T1' ? 'Cursor Auto' : 'Cursor Max/Auto',
                    role: 'IDE-native edits, refactors, and codebase navigation',
                    contextWindow: tier === 'T1' ? 'auto' : '200K+',
                    selected: selectedClient === 'cursor',
                },
            ],
        };
    };
    if (risk === 'critical') {
        return {
            workerTier: 'T3',
            reviewerTier: 'T4',
            ...provider('T3', 'claude'),
            reason: 'Critical-risk task requires a strong worker and rare escalation reviewer.',
            estimatedCostUsd: 0,
            confidence,
            escalationPolicy: ['guardrail-block', 'review-gate-block', 'verification-failure', 'user-approval-required'],
        };
    }
    if (risk === 'high' || workerCount > 2) {
        return {
            workerTier: 'T2',
            reviewerTier: 'T3',
            ...provider('T2', workerCount > 2 ? 'codex' : 'cursor'),
            reason: 'High-risk or multi-worker task gets normal workers with stronger review.',
            estimatedCostUsd: 0,
            confidence,
            escalationPolicy: ['low-confidence', 'verification-failure', 'large-diff'],
        };
    }
    if (risk === 'medium') {
        return {
            workerTier: 'T2',
            reviewerTier: 'T2',
            ...provider('T2', 'cursor'),
            reason: 'Bounded implementation task can run on the standard worker tier.',
            estimatedCostUsd: 0,
            confidence,
            escalationPolicy: ['verification-failure', 'unexpected-diff'],
        };
    }
    return {
        workerTier: 'T1',
        reviewerTier: 'T2',
        ...provider('T1', 'cursor'),
        reason: 'Low-risk routing and summarization should use cheap execution with normal review.',
        estimatedCostUsd: 0,
        confidence,
        escalationPolicy: ['low-confidence'],
    };
}
function normalizeTools(values) {
    return unique(values.flatMap((value) => Array.isArray(value) ? value : [value]), 30);
}
function resolveCostGuardrailUsd(task, run, risk) {
    const explicit = Number(task.budgetCapUsd ?? task.maxCostUsd ?? run.budgetCapUsd ?? run.maxCostUsd);
    if (Number.isFinite(explicit) && explicit > 0)
        return Math.min(50, Math.max(0.25, explicit));
    if (risk === 'critical')
        return 20;
    if (risk === 'high')
        return 10;
    if (risk === 'medium')
        return 3;
    return 1;
}
function buildAgentFlowPolicy(input) {
    const budget = resolveCostGuardrailUsd(input.task, input.run, input.risk);
    const reviewerTier = input.modelRoute.reviewerTier ?? input.modelRoute.workerTier;
    const stages = [
        {
            stage: 'research',
            ownerRole: 'planner',
            gate: 'request brief, memory recall, and candidate context selected',
            modelTier: reviewerTier,
            budgetShare: 0.12,
        },
        {
            stage: 'build',
            ownerRole: 'coder',
            gate: 'owned files only, small diff, no unrelated churn',
            modelTier: input.modelRoute.workerTier,
            budgetShare: input.workerCount > 1 ? 0.44 : 0.5,
        },
        {
            stage: 'review',
            ownerRole: input.reviewMode === 'none' ? 'verifier' : 'reviewer',
            gate: input.reviewMode === 'none'
                ? 'self-check only for low-risk advisory work'
                : 'adversarial review must identify risks before pass',
            modelTier: reviewerTier,
            budgetShare: input.reviewMode === 'none' ? 0.08 : 0.16,
        },
        {
            stage: 'test',
            ownerRole: 'verifier',
            gate: input.verificationRequired ? 'targeted tests/build/lint required' : 'verification optional unless files changed',
            modelTier: reviewerTier,
            budgetShare: 0.14,
        },
        {
            stage: 'integrate',
            ownerRole: 'integrator',
            gate: input.workerCount > 1 ? 'merge independent packets and check conflicts' : 'summarize single-lane result',
            modelTier: reviewerTier,
            budgetShare: 0.1,
        },
        {
            stage: 'done',
            ownerRole: 'verifier',
            gate: 'record verification, memory write-back, and residual risk',
            modelTier: reviewerTier,
            budgetShare: 0.08,
        },
    ];
    return {
        enabled: true,
        boardSource: 'nexus-runtime',
        maxTaskCostUsd: budget,
        hardStopUsd: Math.max(budget, Math.min(50, budget * 2)),
        crashRecovery: 'Persist run state, decision-spine artifacts, and worker lanes so the next sweep can resume.',
        dispatchPolicy: input.workerCount > 1
            ? 'bounded parallel lanes with one owner per file and deterministic gates before AI review'
            : 'single worker lane with planner and verifier checkpoints',
        deterministicGates: unique([
            'build',
            'lint',
            'test',
            input.reviewMode !== 'none' ? 'adversarial-review' : '',
            input.workerCount > 1 ? 'integration-conflict-check' : '',
        ], 8),
        stages,
    };
}
export function buildExecutionPolicy(input) {
    const task = input.task ?? {};
    const run = input.run ?? {};
    const planner = input.plannerState ?? run.plannerState ?? {};
    const risk = input.risk ?? run.requestBrief?.risk ?? inferRisk(task);
    const modelRoute = input.modelRoute ?? inferModelRoute({ task, run, risk });
    const workerCount = Math.max(1, Number(task.workers ?? run.workerManifests?.filter((manifest) => manifest.role === 'coder').length ?? 1));
    const allowedTools = normalizeTools([
        ...(task.allowedToolsOverride ?? []),
        ...(planner.toolPolicy?.allowedTools ?? []),
        ...(run.plannerResult?.selectedTools ?? []),
    ]);
    const tools = allowedTools.length ? allowedTools : (risk === 'low' ? ['read_file', 'run_command'] : ['read_file', 'write_file', 'append_file', 'replace_text', 'run_command']);
    const reviewMode = risk === 'critical'
        ? 'escalated-review'
        : risk === 'high' || workerCount > 1
            ? 'reviewer'
            : risk === 'medium'
                ? 'self-check'
                : 'none';
    const topology = String(task.topology ?? planner.swarmDecision?.mode ?? 'auto');
    const coderTier = modelRoute.workerTier;
    const reviewerTier = modelRoute.reviewerTier ?? modelRoute.workerTier;
    const verificationRequired = reviewMode !== 'none' || (task.verifyCommands ?? []).length > 0;
    return {
        topology,
        workerCount,
        maxParallelWorkers: topology === 'dag-pool' || topology === 'worktree-swarm'
            ? Math.max(1, Math.min(workerCount, 7))
            : Math.max(1, Math.min(workerCount, 3)),
        allowedTools: tools,
        subagents: [
            { role: 'planner', modelTier: reviewerTier, authority: 'read', reviewRequired: false },
            { role: 'coder', modelTier: coderTier, authority: tools.some((tool) => /write|append|replace|run_command/.test(tool)) ? 'write' : 'read', reviewRequired: reviewMode !== 'none' },
            { role: 'verifier', modelTier: reviewerTier, authority: 'verify', reviewRequired: false },
        ],
        verificationRequired,
        reviewMode,
        escalationPolicy: modelRoute.escalationPolicy,
        reasons: unique([
            modelRoute.reason,
            planner.toolPolicy?.reasons?.join(' '),
            risk === 'critical' ? 'Critical risk keeps reviewer escalation mandatory.' : '',
            workerCount > 1 ? 'Multiple workers require bounded parallelism and verifier coverage.' : '',
            (task.verifyCommands ?? []).length > 0 ? 'Explicit verification commands were provided.' : '',
        ], 8),
        agentFlow: buildAgentFlowPolicy({
            task,
            run,
            risk,
            workerCount,
            modelRoute,
            reviewMode,
            verificationRequired,
        }),
    };
}
export function buildRequestBrief(input) {
    const task = input.task;
    const intent = normalizeIntent(task.intent);
    const risk = inferRisk(task);
    const createdAt = input.createdAt ?? Date.now();
    const specialists = input.plannerState?.selectedSpecialists ?? [];
    return {
        schemaVersion: 1,
        id: `brief_${input.runId}`,
        runId: input.runId,
        rawPrompt: String(task.goal ?? ''),
        rewrittenPrompt: short(task.goal, 2000),
        intent,
        confidence: task.intent ? 0.82 : 0.62,
        risk,
        artifactType: inferArtifactType(intent, task),
        constraints: unique([
            ...(task.files ?? []).map((file) => `file:${file}`),
            ...(task.verifyCommands ?? []).map((command) => `verify:${command}`),
            ...(task.manualOverrides ?? []).map((command) => `manual:${command}`),
        ], 40),
        acceptanceCriteria: unique(task.successCriteria ?? [], 20),
        openQuestions: [],
        taskClass: String(task.executionMode ?? 'runtime'),
        candidateMemories: [],
        candidateFiles: unique(task.files ?? [], 40),
        candidateSkills: unique([...(task.skillNames ?? []), ...(input.plannerState?.selectedSkills ?? [])], 40),
        candidateAgents: unique(specialists.map((specialist) => specialist.name ?? specialist.specialistId), 20),
        modelPolicy: inferModelRoute({ task, risk, confidence: task.intent ? 0.82 : 0.62 }),
        createdAt,
    };
}
function buildBudgets(run, task, readingPlan) {
    const repoTokens = Number(readingPlan?.totalEstimatedTokens ?? run.tokenTelemetry?.forwardedTokens ?? 0);
    const promptText = String(task.goal ?? '');
    const detectedBlocks = Math.floor((promptText.match(/```/g) ?? []).length / 2);
    const languages = unique([...promptText.matchAll(/```([a-z0-9_-]+)/gi)].map((match) => match[1]), 8);
    const wantsCodeBlocks = detectedBlocks > 0 || /(code blocks?|template|patch|diff|snippet|implementation|coding quality|work quality)/i.test(promptText);
    const templateBlocks = wantsCodeBlocks ? 4 : 2;
    const codeBlockTokens = Math.min(2400, Math.max(360, detectedBlocks * 320 + templateBlocks * 220));
    const skillTokens = Math.min(1600, Math.max(400, (run.activeSkills?.length ?? 0) * 220 + (run.activeWorkflows?.length ?? 0) * 180));
    const promptTokens = Math.min(1600, Math.max(200, Math.ceil(promptText.length / 4)));
    const memoryTokens = Math.min(2400, Math.max(300, (run.backendEvidence?.memory?.recalled?.length ?? 0) * 300));
    const graphTokens = run.knowledgeFabric ? 800 : 0;
    const runtimeTokens = run.executionLedger ? 600 : 0;
    const risk = run.requestBrief?.risk ?? inferRisk(task);
    const reasoningTokens = risk === 'critical' ? 1800 : risk === 'high' ? 1400 : risk === 'medium' ? 900 : 500;
    const verificationTokens = Math.min(1600, Math.max(260, (task.verifyCommands?.length ?? run.workerManifests?.length ?? 1) * 180));
    const reserve = Math.max(500, Math.ceil((repoTokens + memoryTokens + codeBlockTokens) * 0.1));
    const totalTokens = repoTokens
        + promptTokens
        + memoryTokens
        + graphTokens
        + runtimeTokens
        + skillTokens
        + reasoningTokens
        + codeBlockTokens
        + verificationTokens
        + reserve;
    return {
        totalTokens,
        prompt: promptTokens,
        memory: memoryTokens,
        repo: Math.max(0, repoTokens),
        graph: run.knowledgeFabric ? 800 : 0,
        runtime: run.executionLedger ? 600 : 0,
        skills: skillTokens,
        reasoning: reasoningTokens,
        codeBlocks: codeBlockTokens,
        verification: verificationTokens,
        reserve,
        codeBlockPolicy: {
            detectedBlocks,
            templateBlocks,
            reservedTokens: codeBlockTokens,
            languages: languages.length ? languages : ['markdown', 'text'],
            templates: [
                'work-packet',
                'implementation-notes',
                'verification-output',
                'memory-writeback',
            ].slice(0, templateBlocks),
        },
    };
}
export function buildSelectionPlan(input) {
    const { run, task } = input;
    const planner = run.plannerResult ?? {};
    const plannerState = input.plannerState ?? run.plannerState ?? {};
    const selectedFiles = unique([
        ...(planner.selectedFiles ?? []),
        ...(input.fileRefs ?? []).map((file) => file.path),
        ...(task.files ?? []),
    ]);
    const selectedSkills = unique([
        ...(planner.selectedSkills ?? []),
        ...(run.activeSkills ?? []).map((skill) => skill.name ?? skill.skillId),
    ]);
    const selectedWorkflows = unique([
        ...(planner.selectedWorkflows ?? []),
        ...(run.activeWorkflows ?? []).map((workflow) => workflow.name ?? workflow.workflowId),
    ]);
    const selectedSpecialists = unique([
        ...(planner.selectedSpecialists ?? []).map((specialist) => specialist.name ?? specialist.specialistId),
        ...(run.workerManifests ?? []).map((manifest) => manifest.specialistName ?? manifest.specialistId),
    ]);
    const selectedCrews = unique([
        planner.selectedCrew?.name,
        plannerState.selectedCrew?.name,
        planner.selectedCrew?.crewId,
        plannerState.selectedCrew?.crewId,
    ]);
    const selectedActions = unique((run.workerManifests ?? [])
        .flatMap((manifest) => manifest.actions ?? [])
        .map(actionName), 40);
    const verifyCommands = unique((run.workerManifests ?? []).flatMap((manifest) => manifest.verifyCommands ?? []), 40);
    const changedFiles = extractChangedFiles(run);
    const modelRoute = inferModelRoute({ task, run, risk: run.requestBrief?.risk });
    const executionPolicy = buildExecutionPolicy({ task, run, plannerState, modelRoute, risk: run.requestBrief?.risk });
    const selectedSet = {
        files: selectedFiles,
        memories: unique(input.memoryMatches ?? [], 20),
        skills: selectedSkills,
        workflows: selectedWorkflows,
        hooks: unique((run.activeHooks ?? []).map((hook) => hook.name ?? hook.hookId), 40),
        automations: unique((run.activeAutomations ?? []).map((automation) => automation.name ?? automation.automationId), 40),
        specialists: selectedSpecialists,
        crews: selectedCrews,
        workers: unique((run.workerManifests ?? []).map((manifest) => manifest.workerId), 40),
        verifyCommands,
        actions: selectedActions,
        changedFiles,
    };
    const plan = {
        schemaVersion: 1,
        id: `plan_${run.runId}`,
        runId: run.runId,
        requestBriefId: run.requestBrief?.id,
        workspaceKey: run.executionLedger?.workspace?.stateKey ?? undefined,
        intent: normalizeIntent(task.intent ?? run.requestBrief?.intent),
        topology: String(task.topology ?? 'auto'),
        candidates: {
            files: unique([...(task.files ?? []), ...(input.fileRefs ?? []).map((file) => file.path)], 80),
            memories: unique(input.memoryMatches ?? [], 20),
            skills: unique([...(task.skillNames ?? []), ...(plannerState.selectedSkills ?? [])], 80),
            workflows: unique([...(task.workflowSelectors ?? []), ...(plannerState.selectedWorkflows ?? [])], 80),
            hooks: unique([...(task.hookSelectors ?? []), ...(run.activeHooks ?? []).map((hook) => hook.name ?? hook.hookId)], 40),
            automations: unique([...(task.automationSelectors ?? []), ...(run.activeAutomations ?? []).map((automation) => automation.name ?? automation.automationId)], 40),
            specialists: selectedSpecialists,
            crews: selectedCrews,
        },
        selected: selectedSet,
        budgets: buildBudgets(run, task, input.readingPlan),
        modelRoute,
        contextRouter: buildContextRouterSnapshot(run, selectedSet),
        executionPolicy,
        riskGates: (planner.reviewGates ?? plannerState.reviewGates ?? []).map((gate) => ({
            gate: String(gate.gate ?? gate.name ?? 'review'),
            status: String(gate.status ?? 'planned'),
            reason: gate.reason ? String(gate.reason) : undefined,
        })),
        provenance: [
            ...selectedFiles.map((file) => ({
                targetType: 'file',
                targetId: file,
                signals: [{ source: 'planner', score: 0.75, reason: 'Selected by planner/file discovery for this run.' }],
            })),
            ...selectedSkills.map((skill) => ({
                targetType: 'skill',
                targetId: skill,
                signals: [{ source: 'catalog', score: 0.7, reason: 'Selected by runtime catalog resolution.' }],
            })),
            {
                targetType: 'model',
                targetId: modelRoute.workerTier,
                signals: [{ source: 'runtime', score: modelRoute.confidence, reason: modelRoute.reason }],
            },
        ],
        confidence: Math.min(0.98, Math.max(0.35, (run.requestBrief?.confidence ?? 0.7) + (selectedFiles.length > 0 ? 0.08 : 0))),
        createdAt: input.createdAt ?? Date.now(),
    };
    return plan;
}
export function buildContextLog(run, createdAt = Date.now()) {
    const planId = run.selectionPlan?.id;
    const selected = run.selectionPlan?.selected ?? {};
    const router = run.selectionPlan?.contextRouter ?? buildContextRouterSnapshot(run, selected);
    const changedFiles = unique([...(router.changedFiles ?? []), ...(selected.changedFiles ?? [])], 80);
    return [
        {
            schemaVersion: 1,
            id: `ctx_${run.runId}_compile`,
            runId: run.runId,
            planId,
            actor: 'system',
            phase: 'compile',
            contextRefs: [REQUEST_BRIEF_FILE],
            memoryRefs: [],
            fileRefs: [],
            changedFiles: [],
            evidenceRefs: ['task.json', 'planner-state.json'],
            reason: 'Compiled the raw user goal into a durable request brief.',
            createdAt,
        },
        {
            schemaVersion: 1,
            id: `ctx_${run.runId}_select`,
            runId: run.runId,
            planId,
            actor: 'system',
            phase: 'select',
            contextRefs: [SELECTION_PLAN_FILE, 'reading-plan.json'],
            memoryRefs: selected.memories ?? [],
            fileRefs: selected.files ?? [],
            changedFiles: [],
            evidenceRefs: ['planner-result.json', 'skills.json', 'workflows.json'],
            reason: `Selected ${selected.files?.length ?? 0} file(s), ${selected.crews?.length ?? 0} crew(s), ${selected.specialists?.length ?? 0} specialist(s), and model ${run.selectionPlan?.modelRoute?.workerTier ?? 'T1'}.`,
            createdAt,
        },
        {
            schemaVersion: 1,
            id: `ctx_${run.runId}_route`,
            runId: run.runId,
            planId,
            actor: 'context-router',
            phase: 'route',
            contextRefs: [SELECTION_PLAN_FILE, 'manifests.json'],
            memoryRefs: selected.memories ?? [],
            fileRefs: unique([...(selected.files ?? []), ...changedFiles], 80),
            changedFiles,
            evidenceRefs: ['manifests.json', 'worker-results.json'],
            reason: `Context router status: ${router.status}. ${router.workersExecuted}/${router.workersPlanned} worker(s) executed, ${router.actionsBound} action binding(s), ${router.workersVerified} verified worker(s). ${router.reason}`,
            createdAt,
        },
        {
            schemaVersion: 1,
            id: `ctx_${run.runId}_execute`,
            runId: run.runId,
            planId,
            actor: 'worker',
            phase: 'execute',
            contextRefs: ['manifests.json'],
            memoryRefs: [],
            fileRefs: unique([...(selected.files ?? []), ...changedFiles], 80),
            changedFiles,
            evidenceRefs: ['worker-results.json'],
            reason: `${run.workerResults?.length ?? 0} worker result(s) recorded; ${router.actionsBound} executable action binding(s) were available.`,
            createdAt,
        },
        {
            schemaVersion: 1,
            id: `ctx_${run.runId}_verify`,
            runId: run.runId,
            planId,
            actor: 'reviewer',
            phase: 'verify',
            contextRefs: ['verification-results.json'],
            memoryRefs: [],
            fileRefs: unique([...(selected.files ?? []), ...changedFiles], 80),
            changedFiles,
            evidenceRefs: ['verification-results.json', 'decision.json'],
            reason: `${router.workersVerified}/${run.verificationResults?.length ?? 0} verification result(s) passed.`,
            createdAt,
        },
        {
            schemaVersion: 1,
            id: `ctx_${run.runId}_summarize`,
            runId: run.runId,
            planId,
            actor: 'system',
            phase: 'summarize',
            contextRefs: [USER_WORKFLOW_TRACE_REF],
            memoryRefs: unique((run.memoryChecks ?? []).map((entry) => entry.memoryId ?? entry.id), 20),
            fileRefs: unique([...(selected.files ?? []), ...changedFiles], 80),
            changedFiles,
            evidenceRefs: ['run.json', 'token-telemetry.json'],
            reason: changedFiles.length
                ? `${changedFiles.length} changed file(s): ${short(changedFiles.join(', '), 420)}`
                : short(run.result, 500),
            createdAt,
        },
    ];
}
const USER_WORKFLOW_TRACE_REF = 'user-workflow-trace.json';
export function buildDecisionLog(run, createdAt = Date.now()) {
    const selected = run.selectionPlan?.selected ?? {};
    const router = run.selectionPlan?.contextRouter ?? buildContextRouterSnapshot(run, selected);
    const changedFiles = unique([...(router.changedFiles ?? []), ...(selected.changedFiles ?? [])], 80);
    return [
        {
            schemaVersion: 1,
            id: `dec_${run.runId}_plan`,
            runId: run.runId,
            actor: 'nexus-prime',
            surface: 'runtime',
            verb: 'plan',
            decision: `Selected ${selected.files?.length ?? 0} file(s), ${selected.skills?.length ?? 0} skill(s), ${selected.crews?.length ?? 0} crew(s), ${selected.specialists?.length ?? 0} specialist(s), and model ${run.selectionPlan?.modelRoute?.workerTier ?? 'T1'}.`,
            reason: run.selectionPlan?.modelRoute?.reason ?? 'Runtime generated a baseline selection plan.',
            afterRef: SELECTION_PLAN_FILE,
            createdAt,
        },
        {
            schemaVersion: 1,
            id: `dec_${run.runId}_route`,
            runId: run.runId,
            actor: 'nexus-prime-context-router',
            surface: 'runtime',
            verb: 'route',
            decision: `Route status ${router.status}: ${router.workersExecuted}/${router.workersPlanned} worker(s), ${router.actionsBound} action binding(s), ${changedFiles.length} changed file(s).`,
            reason: router.reason,
            beforeRef: SELECTION_PLAN_FILE,
            afterRef: 'manifests.json',
            changedFiles,
            createdAt,
        },
        {
            schemaVersion: 1,
            id: `dec_${run.runId}_execute`,
            runId: run.runId,
            actor: 'nexus-prime',
            surface: 'runtime',
            verb: 'execute',
            decision: `${router.workersExecuted} worker(s) executed with ${router.actionsBound} executable action binding(s).`,
            reason: router.actionsBound > 0
                ? 'Runtime dispatched worker manifests from the selection plan.'
                : 'Selected workers produced advisory output only; no mutation bindings were available for this route.',
            beforeRef: 'manifests.json',
            afterRef: 'worker-results.json',
            changedFiles,
            createdAt,
        },
        {
            schemaVersion: 1,
            id: `dec_${run.runId}_verify`,
            runId: run.runId,
            actor: 'nexus-prime',
            surface: 'runtime',
            verb: 'verify',
            decision: `${run.verificationResults?.filter((entry) => entry.status === 'passed').length ?? 0}/${run.verificationResults?.length ?? 0} verification result(s) passed.`,
            reason: 'Verification results and merge decision were recorded before final outcome.',
            beforeRef: 'worker-results.json',
            afterRef: 'verification-results.json',
            changedFiles,
            createdAt,
        },
        {
            schemaVersion: 1,
            id: `dec_${run.runId}_changes`,
            runId: run.runId,
            actor: 'nexus-prime',
            surface: 'runtime',
            verb: 'change',
            decision: changedFiles.length
                ? `Changed ${changedFiles.length} file(s).`
                : 'No file changes recorded.',
            reason: changedFiles.length
                ? short(changedFiles.join(', '), 500)
                : 'The run completed without a candidate repository diff or command-produced file set.',
            beforeRef: 'decision.json',
            afterRef: changedFiles.length ? 'final.patch' : 'run.json',
            changedFiles,
            createdAt,
        },
        {
            schemaVersion: 1,
            id: `dec_${run.runId}_complete`,
            runId: run.runId,
            actor: 'nexus-prime',
            surface: 'runtime',
            verb: 'complete',
            decision: `Run completed with state ${run.state}.`,
            reason: short(run.result, 500),
            beforeRef: 'decision.json',
            afterRef: 'run.json',
            changedFiles,
            createdAt,
        },
    ];
}
export function toJsonl(entries) {
    return `${entries.map((entry) => JSON.stringify(entry)).join('\n')}\n`;
}
