/*
 * Copyright 2026, Jaime Terrats.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { listRecords } from './orchestration-records.js';
import { readWorkspaceConfig } from './workspace-config.js';
// ─── Contract Registry ───────────────────────────────────────────────────────
export const CONTRACT_REGISTRY = {
    ta: {
        role: 'ta',
        requiredChecks: ['evidence', 'decision'],
        mode: 'warn',
        requiredFields: [
            { field: 'rationale', description: 'Architecture decision rationale' },
            { field: 'alternatives', description: 'Considered alternatives' },
        ],
    },
    developer: {
        role: 'developer',
        requiredChecks: ['evidence'],
        mode: 'warn',
        requiredFields: [{ field: 'changedFiles', description: 'List of changed files' }],
    },
    qa: {
        role: 'qa',
        requiredChecks: ['evidence'],
        mode: 'warn',
        requiredFields: [{ field: 'testResults', description: 'Test execution results' }],
    },
    security: {
        role: 'security',
        requiredChecks: ['evidence', 'decision'],
        mode: 'escalate',
        requiredFields: [
            { field: 'threatModel', description: 'Threat model assessment' },
            { field: 'mitigations', description: 'Applied security mitigations' },
        ],
        domainEscalation: {
            domains: ['healthcare', 'financial_services', 'government', 'defense'],
            additionalChecks: ['compliance-review', 'data-classification'],
            escalationLevel: 'critical',
        },
    },
    releaseManager: {
        role: 'release_manager',
        requiredChecks: ['evidence'],
        mode: 'block',
        requiredFields: [
            { field: 'releaseNotes', description: 'Release notes summary' },
            { field: 'rollbackPlan', description: 'Rollback plan' },
        ],
    },
};
// Backward-compatible flat array derived from the registry
const DEFAULT_CONTRACTS = Object.values(CONTRACT_REGISTRY);
// ─── Generic phrase detection ───────────────────────────────────────────────
const GENERIC_PHRASES = new Set([
    'no gaps',
    'no risks',
    'none',
    'n/a',
    'ready',
    'no issues',
    'all good',
    'looks good',
    'lgtm',
    'done',
    'complete',
    'completed',
]);
/**
 * Resolves the applicable quality contract for a given phase/profile.
 * Checks workspace config first; falls back to defaults.
 */
export function resolveQualityContract(cwd, phase, profile) {
    const config = readWorkspaceConfig(cwd);
    const customContracts = config?.qualityContracts;
    if (customContracts && customContracts.length > 0) {
        const match = customContracts.find((c) => c.role === profile || c.role === phase);
        if (match)
            return match;
    }
    const defaultMatch = DEFAULT_CONTRACTS.find((c) => c.role === profile || c.role === phase);
    if (defaultMatch)
        return defaultMatch;
    return { role: profile, requiredChecks: [], mode: 'advisory' };
}
/**
 * Validates whether a task has sufficient evidence/decisions for a handoff.
 */
export function validateHandoffQuality(cwd, storyId, phase, profile) {
    const contract = resolveQualityContract(cwd, phase, profile);
    const violations = [];
    for (const check of contract.requiredChecks) {
        if (check === 'evidence') {
            const records = listRecords(cwd, 'evidence');
            const relevant = records.filter((r) => r.taskIds.includes(storyId));
            if (relevant.length === 0) {
                violations.push(`Missing required evidence for task ${storyId}`);
            }
        }
        else if (check === 'decision') {
            const records = listRecords(cwd, 'decision');
            const relevant = records.filter((r) => r.taskIds.includes(storyId));
            if (relevant.length === 0) {
                violations.push(`Missing required decision for task ${storyId}`);
            }
        }
        else {
            // Extensible: treat unknown checks as missing
            violations.push(`Missing required check "${check}" for task ${storyId}`);
        }
    }
    return {
        passed: violations.length === 0,
        violations,
        mode: contract.mode,
    };
}
/**
 * Validates handoff content to reject generic/empty summaries.
 */
export function validateHandoffContent(summary, evidenceIds) {
    const warnings = [];
    const trimmed = summary.trim();
    if (!trimmed || trimmed.length < 20) {
        warnings.push(`Handoff summary is too short (${trimmed.length} chars, minimum 20)`);
    }
    if (trimmed && GENERIC_PHRASES.has(trimmed.toLowerCase())) {
        warnings.push(`Handoff summary contains only generic content: "${trimmed}"`);
    }
    if (evidenceIds.length === 0) {
        warnings.push('No evidence IDs provided with handoff');
    }
    return {
        valid: warnings.length === 0,
        warnings,
    };
}
// ─── Per-Phase Required Field Validation ──────────────────────────────────────
/**
 * Validates that all required fields defined in a contract are present in the
 * provided field set.
 */
export function validateRequiredFields(contract, providedFields) {
    if (!contract.requiredFields || contract.requiredFields.length === 0) {
        return { valid: true, missing: [] };
    }
    const missing = contract.requiredFields.filter((rf) => !providedFields.has(rf.field));
    return { valid: missing.length === 0, missing };
}
// ─── Escalation ───────────────────────────────────────────────────────────────
/**
 * Emits a structured escalation event to stderr for consumption by
 * orchestration tooling or observability pipelines.
 */
export function emitEscalation(event) {
    process.stderr.write(JSON.stringify(event) + '\n');
}
// ─── Domain Escalation ────────────────────────────────────────────────────────
/**
 * Applies domain-specific escalation rules to a contract when the workspace
 * operates in a regulated domain. Returns a new contract with additional
 * checks merged and mode elevated to 'escalate' if applicable.
 */
export function applyDomainEscalation(contract, workspaceDomains) {
    if (!contract.domainEscalation)
        return contract;
    if (workspaceDomains.length === 0)
        return contract;
    const matchingDomains = workspaceDomains.filter((d) => contract.domainEscalation.domains.includes(d));
    if (matchingDomains.length === 0)
        return contract;
    // Merge additional checks without duplicates
    const mergedChecks = [...new Set([...contract.requiredChecks, ...contract.domainEscalation.additionalChecks])];
    return {
        ...contract,
        requiredChecks: mergedChecks,
        mode: 'escalate',
    };
}
/**
 * Returns a contract for a role with domain escalation applied from workspace config.
 */
export function resolveQualityContractWithDomain(cwd, phase, profile) {
    const baseContract = resolveQualityContract(cwd, phase, profile);
    const config = readWorkspaceConfig(cwd);
    const workspaceDomains = config?.domains ?? [];
    return applyDomainEscalation(baseContract, workspaceDomains);
}
//# sourceMappingURL=quality-contracts.js.map