/**
 * Pack Inheritance (W1.3 of F-NEW-PRODUCT-AGENT-VISIBILITY-CLUSTER-2026-05-12).
 *
 * Lets a customer declare org-wide rules ONCE at the org-baseline pack
 * (e.g. "no agent deletes a DB without approval", "no MCP across the
 * fleet") and inherit them into every per-agent company pack with optional
 * per-agent additions on top.
 *
 * Inheritance semantics:
 *   - Org-baseline rules apply to ALL agents in the org by default.
 *   - Per-agent pack adds agent-specific rules.
 *   - When the same capability class appears in both, STRICTEST-WINS.
 *   - Composed pack carries provenance pointers to both source pack IDs.
 *
 * Composition produces a single CompliancePackWithClassifiers that can be
 * activated per-agent in PackRegistry. Single-pack activation is intentional
 * — customers can stay with one pack-per-agent mental model while still
 * getting org-wide rule propagation under the hood.
 *
 * @connexum/ai-governance  F-NEW-PRODUCT-PACK-INHERITANCE
 */
import { buildCompanyPack, } from './company-pack-builder.js';
const ACTION_RANK = {
    ALLOW: 0,
    LOG: 1,
    WARN: 2,
    REQUIRE_APPROVAL: 3,
    BLOCK: 4,
};
/**
 * Build an org-baseline pack. Conceptually identical to a company pack except
 * that its rules apply to every agent in the org by inheritance.
 */
export function buildOrgBaselinePack(input) {
    const baselineId = input.id ?? `org-baseline-${input.orgId}`;
    return buildCompanyPack({
        id: baselineId,
        name: input.name ?? `${input.orgId} org-wide baseline`,
        orgId: input.orgId,
        rules: input.rules,
        isolation: input.isolation,
        description: `Org-baseline pack for ${input.orgId} — inherited by all per-agent packs`,
    });
}
/**
 * Compose org-baseline + per-agent rules into one pack with strictest-wins
 * semantics on every category. Tracks provenance via `aliases` so audit tooling
 * can identify both sources.
 *
 * Per-agent overrides (W1.9) skip strictest-wins for the named capability:
 * the override's relaxed action replaces whatever strictest-wins would have
 * produced. Each override emits an OverrideEvent via the optional sink.
 */
export function composeAgentPack(baseline, agentInput, options) {
    validateOverrides(agentInput.overrides);
    const agentDelta = buildCompanyPack({
        id: agentInput.id,
        name: agentInput.name,
        orgId: agentInput.orgId,
        rules: agentInput.rules,
        isolation: agentInput.isolation,
        description: `Per-agent pack for ${agentInput.agentId} (inherits from ${baseline.id})`,
    });
    // Strictest-wins merge of categoryActions.
    const baselineActions = baseline.dataPolicy?.categoryActions ?? {};
    const agentActions = agentDelta.dataPolicy.categoryActions ?? {};
    const mergedActions = {};
    // W1.9 override lookup — capability -> override descriptor.
    const overrideMap = new Map();
    for (const ov of agentInput.overrides ?? []) {
        overrideMap.set(ov.capability, ov);
    }
    const composedAt = new Date().toISOString();
    const overrideEvents = [];
    const allKeys = new Set([
        ...Object.keys(baselineActions),
        ...Object.keys(agentActions),
        ...overrideMap.keys(),
    ]);
    for (const key of allKeys) {
        const ov = overrideMap.get(key);
        if (ov) {
            // W1.9 — override skips strictest-wins for this capability.
            mergedActions[key] = ov.action;
            const overrideId = ov.overrideId ?? `${agentInput.agentId}::${key}::${ov.approvedAt}`;
            overrideEvents.push({
                overrideId,
                orgId: agentInput.orgId,
                agentId: agentInput.agentId,
                capability: key,
                baselineAction: baselineActions[key],
                relaxedAction: ov.action,
                approver: ov.approver,
                justification: ov.justification,
                approvedAt: ov.approvedAt,
                composedAt,
            });
            continue;
        }
        const a = baselineActions[key];
        const b = agentActions[key];
        if (a === undefined)
            mergedActions[key] = b;
        else if (b === undefined)
            mergedActions[key] = a;
        else {
            const actA = a;
            const actB = b;
            const rankA = ACTION_RANK[actA] ?? 0;
            const rankB = ACTION_RANK[actB] ?? 0;
            mergedActions[key] = rankB > rankA ? actB : actA;
        }
    }
    if (options?.onOverride) {
        for (const ev of overrideEvents)
            options.onOverride(ev);
    }
    // Merge classifiers: prefer agent's classifier if present, otherwise baseline's.
    const baselineClassifiers = baseline.categoryClassifiers ?? {};
    const agentClassifiers = agentDelta.categoryClassifiers ?? {};
    const mergedClassifiers = { ...baselineClassifiers };
    for (const [k, v] of Object.entries(agentClassifiers)) {
        mergedClassifiers[k] = v;
    }
    // Strictest isolation across the two packs.
    const baselineIso = baseline.requiresActionIsolation;
    const agentIso = agentDelta.requiresActionIsolation;
    const isolationRank = { none: 0, 'sourced-only': 1, strict: 2 };
    const isoA = isolationRank[String(baselineIso ?? 'none')] ?? 0;
    const isoB = isolationRank[String(agentIso ?? 'none')] ?? 0;
    const mergedIsolation = isoB > isoA ? agentIso : baselineIso;
    const composed = {
        ...agentDelta,
        aliases: [baseline.id, agentDelta.id],
        description: `Composed pack: agent ${agentInput.agentId} extends baseline ${baseline.id}. ` +
            `Strictest-wins on overlapping rules.`,
        dataPolicy: {
            ...agentDelta.dataPolicy,
            scanCategories: Object.keys(mergedActions),
            categoryActions: mergedActions,
        },
        categoryClassifiers: mergedClassifiers,
        requiresActionIsolation: mergedIsolation,
    };
    return composed;
}
/**
 * Convenience: build baseline + compose into per-agent pack in one call.
 */
export function buildInheritedAgentPack(baselineInput, agentInput) {
    const baseline = buildOrgBaselinePack(baselineInput);
    const composed = composeAgentPack(baseline, agentInput);
    return { baseline, composed };
}
function validateOverrides(overrides) {
    if (!overrides)
        return;
    for (const ov of overrides) {
        if (!ov.approver || ov.approver.trim() === '') {
            throw new Error(`PerAgentOverride for capability '${ov.capability}' is missing an approver. ` +
                'Overrides require explicit employee approval per F-NEW-PRODUCT-PER-AGENT-OVERRIDE-AUTHORITY.');
        }
        if (!ov.justification || ov.justification.trim() === '') {
            throw new Error(`PerAgentOverride for capability '${ov.capability}' is missing a justification. ` +
                'Overrides must record the reason in the audit chain.');
        }
        if (!ov.approvedAt || !/^\d{4}-\d{2}-\d{2}T/.test(ov.approvedAt)) {
            throw new Error(`PerAgentOverride for capability '${ov.capability}' has invalid approvedAt. ` +
                'Expect ISO 8601 timestamp.');
        }
    }
}
//# sourceMappingURL=pack-inheritance.js.map