/**
 * CapabilityChangeDetector -- Hash-based capability change detection with
 * auto-suspension and versioned attestation history.
 *
 * Implements BUILD_PLAN_V3_FULL_LIFECYCLE.md lines 285-289 (Tier 3
 * self-learning governance):
 *   Line 285: Agent capability change detection.
 *   Line 286: Automatic suspension on undocumented capability change.
 *   Line 287: Approval queue entry for documented capability changes,
 *             requiring re-attestation workflow.
 *   Line 288: Versioned audit of agent capability over time.
 *   Line 289: Refusal-to-operate mode if capability evolution is configured
 *             without the attestation workflow enabled.
 *
 * Three-state model:
 *   verified           -- current hash matches latest registered version.
 *   pending-attestation -- hash changed; attestation workflow ENABLED;
 *                          agent runs at Level 0 until operator resolves.
 *   suspended          -- hash changed; attestation workflow NOT enabled
 *                          (or operator denied); agent refuses all calls.
 *
 * Refusal-to-operate (line 289):
 *   Strict packs (HIPAA, GDPR, PCI DSS, HMDA, DORA) require the
 *   attestation workflow to be enabled when capability-evolution-allowed
 *   is set. Without it, every runtime invocation throws
 *   CapabilityEvolutionWithoutAttestationWorkflowError.
 *
 * Capability hash inputs (canonicalized, sorted):
 *   orgId + agentId + toolset (sorted) + permissions (sorted) +
 *   webAccessTier + hookProfile + autonomyLevel + packBindings (sorted).
 *
 * Audit chain: every event includes prevSha for SHA-256 chaining.
 * History integrity: each version entry references the SHA of the prior
 * entry; tampering breaks the chain and emits CAPABILITY_HISTORY_TAMPERED.
 *
 * Pen-tests shipped:
 *   PT-CAPABILITY-1: hash-collision attack (orgId+agentId scoping).
 *   PT-CAPABILITY-2: history-tampering via chain verification.
 *   PT-CAPABILITY-3: workflow-state forgery from agent runtime context.
 *
 * Compliance bindings:
 *   HIPAA 164.308(a)(3): Workforce authorization and supervision
 *   HIPAA 164.312(c)(1): Integrity controls
 *   SOC 2 CC6.1: Logical access restrictions
 *   SOC 2 CC7.2: System monitoring for tampering
 *   GDPR Art. 22: Automated decision-making controls
 *   DORA Art. 16: ICT risk management -- automation limits
 *   EU AI Act Art. 12: Record-keeping requirements
 *   ISO 27001 A.9.2.3: Management of privileged access
 *   ISO 42001 A.9.1: AI system monitoring
 *   NIST 800-53 AU-12: Audit record generation
 *
 * @connexum/ai-governance P3-T3
 */
import * as crypto from 'node:crypto';
// ---------------------------------------------------------------------------
// Strict pack IDs (require attestation workflow when capability-evolution-allowed)
// ---------------------------------------------------------------------------
export const STRICT_PACK_IDS = new Set([
    'hipaa',
    'hipaa-security',
    'hipaa-privacy',
    '45-cfr-164',
    'gdpr',
    'gdpr-eu',
    'eu-gdpr',
    'pci-dss',
    'pcidss',
    'hmda',
    'dora',
    'dora-eu',
]);
// ---------------------------------------------------------------------------
// Errors
// ---------------------------------------------------------------------------
export class EmptyPackBindingError extends Error {
    operation;
    constructor(operation) {
        super(`Operation '${operation}' requires a non-empty packBinding. ` +
            'Per the Connexum AI Governance pack-binding-primacy invariant, ' +
            'every record must carry at least one compliance pack binding.');
        this.name = 'EmptyPackBindingError';
        this.operation = operation;
    }
}
export class AgentCapabilitySuspendedError extends Error {
    orgId;
    agentId;
    suspendedReason;
    constructor(opts) {
        super(`Agent '${opts.agentId}' in org '${opts.orgId}' is suspended due to an ` +
            `undocumented capability change. No tool invocations, LLM calls, or ` +
            `retrievals are permitted. Reason: ${opts.suspendedReason}. ` +
            `An operator must call recordCapabilityVersion() with the current bundle ` +
            `to explicitly re-register the new capability set before the agent resumes.`);
        this.name = 'AgentCapabilitySuspendedError';
        this.orgId = opts.orgId;
        this.agentId = opts.agentId;
        this.suspendedReason = opts.suspendedReason;
    }
}
export class CapabilityEvolutionWithoutAttestationWorkflowError extends Error {
    orgId;
    agentId;
    strictPacks;
    constructor(opts) {
        super(`CapabilityEvolutionWithoutAttestationWorkflowError: agent '${opts.agentId}' ` +
            `in org '${opts.orgId}' has 'capability-evolution-allowed: true' but the ` +
            `attestation workflow has NOT been enabled. Strict packs active: ` +
            `${opts.strictPacks.join(', ')}. ` +
            `Call enableAttestationWorkflow() before allowing capability evolution ` +
            `on agents bound to strict regulated packs. ` +
            `This is the BUILD_PLAN line-289 refusal-to-operate mode.`);
        this.name = 'CapabilityEvolutionWithoutAttestationWorkflowError';
        this.orgId = opts.orgId;
        this.agentId = opts.agentId;
        this.strictPacks = opts.strictPacks;
    }
}
export class CapabilityAttestationPermissionError extends Error {
    identity;
    constructor(identity, detail) {
        super(`CapabilityAttestationPermissionError: '${identity}' is not authorized ` +
            `to perform capability attestation operations. ` +
            `Requires governance.configure permission (ADMIN role). ` +
            `Detail: ${detail}`);
        this.name = 'CapabilityAttestationPermissionError';
        this.identity = identity;
    }
}
export class CapabilityHistoryTamperedError extends Error {
    orgId;
    agentId;
    brokenAtVersion;
    constructor(opts) {
        super(`CapabilityHistoryTamperedError: version history for agent '${opts.agentId}' ` +
            `in org '${opts.orgId}' has a broken hash chain at version ${opts.brokenAtVersion}. ` +
            `A prior entry was modified or removed. ` +
            `The history is untrusted until an operator reviews and attests.`);
        this.name = 'CapabilityHistoryTamperedError';
        this.orgId = opts.orgId;
        this.agentId = opts.agentId;
        this.brokenAtVersion = opts.brokenAtVersion;
    }
}
// ---------------------------------------------------------------------------
// Genesis sentinel for history chain
// ---------------------------------------------------------------------------
const HISTORY_GENESIS_HASH = crypto
    .createHash('sha256')
    .update('connexum:capability-history:genesis')
    .digest('hex');
// ---------------------------------------------------------------------------
// CapabilityChangeDetector
// ---------------------------------------------------------------------------
export class CapabilityChangeDetector {
    /** State per `${orgId}::${agentId}` */
    agentStates = new Map();
    /** SHA-256 chain state for audit events (simple in-memory chain). */
    lastSha = '';
    /** Audit event callback. */
    onAudit;
    /**
     * Optional injected permission checker.
     * Signature mirrors OperatorRoles.checkPermission.
     */
    checkPermission;
    constructor(opts = {}) {
        this.onAudit = opts.onAudit ?? (() => undefined);
        this.checkPermission = opts.checkPermission;
    }
    // -------------------------------------------------------------------------
    // Public: computeCapabilityHash
    // -------------------------------------------------------------------------
    /**
     * Compute a deterministic SHA-256 hash over the capability bundle.
     *
     * The canonical input includes orgId and agentId so that hash values are
     * scoped to a specific agent -- a hash computed for agent A cannot satisfy
     * the registered hash for agent B even if their bundles are identical.
     * This defeats PT-CAPABILITY-1 (cross-agent hash substitution).
     *
     * Hash inputs (in this order):
     *   orgId, agentId, toolset (sorted), permissions (sorted),
     *   webAccessTier, hookProfile, autonomyLevel, packBindings (sorted).
     */
    computeCapabilityHash(orgId, agentId, bundle) {
        const canonical = {
            orgId,
            agentId,
            toolset: [...bundle.toolset].sort(),
            permissions: [...bundle.permissions].sort(),
            webAccessTier: bundle.webAccessTier,
            hookProfile: bundle.hookProfile,
            autonomyLevel: bundle.autonomyLevel,
            packBindings: [...bundle.packBindings].sort(),
        };
        return crypto
            .createHash('sha256')
            .update(JSON.stringify(canonical))
            .digest('hex');
    }
    // -------------------------------------------------------------------------
    // Public: recordCapabilityVersion (operator-only)
    // -------------------------------------------------------------------------
    /**
     * Register a new capability version for an agent.
     *
     * Operator-only. Computes the bundle hash, appends a new versioned entry
     * to the agent's history, and emits CAPABILITY_VERSION_REGISTERED at
     * severity ERROR.
     *
     * Even a no-op registration (same hash as the previous version) is recorded.
     * Operators may re-register the same bundle to refresh attestation or to
     * explicitly clear a suspension.
     *
     * This is the ONLY way to clear a suspended agent:
     *   1. Operator calls recordCapabilityVersion with the new bundle.
     *   2. Suspension clears.
     *   3. Pending approval entry (if any) is superseded.
     *
     * @throws EmptyPackBindingError if packBinding is empty.
     * @throws CapabilityAttestationPermissionError if identity is not admin.
     */
    recordCapabilityVersion(orgId, agentId, bundle, attesterIdentity, attestationReason, packBinding) {
        this.assertNonEmptyPackBinding(packBinding, 'recordCapabilityVersion');
        this.assertOperatorIdentity(attesterIdentity, 'recordCapabilityVersion');
        const key = this.stateKey(orgId, agentId);
        const state = this.getOrCreateState(key);
        const hash = this.computeCapabilityHash(orgId, agentId, bundle);
        const prevEntry = state.history[state.history.length - 1] ?? null;
        const prevEntryHash = prevEntry
            ? this.hashVersionEntry(prevEntry)
            : HISTORY_GENESIS_HASH;
        const entry = {
            version: state.history.length + 1,
            hash,
            prevEntryHash,
            registeredAt: new Date().toISOString(),
            attesterIdentity,
            attestationReason,
            bundleSnapshot: this.snapshotBundle(bundle),
        };
        // Append to history (immutable from caller's perspective).
        state.history.push(entry);
        // Clear suspension -- explicit registration is the unsuspend path.
        state.suspended = false;
        state.suspendedReason = null;
        state.pendingApprovalId = null;
        this.emit({
            type: 'CAPABILITY_VERSION_REGISTERED',
            severity: 'ERROR',
            orgId,
            agentId,
            packBinding,
            version: entry.version,
            hash: entry.hash,
            attesterIdentity,
            attestationReason,
        });
        return entry;
    }
    // -------------------------------------------------------------------------
    // Public: checkCurrentCapability (runtime check)
    // -------------------------------------------------------------------------
    /**
     * Check whether the current bundle matches the latest registered version.
     *
     * Called at agent startup and on every capability-mutation attempt.
     *
     * Three outcomes:
     *   verified           -- hashes match. Agent operates normally.
     *   pending-attestation -- mismatch + attestation workflow ENABLED.
     *                          Agent runs at Level 0 (degraded) until resolved.
     *   suspended          -- mismatch + attestation workflow NOT enabled.
     *                          Agent must not execute anything.
     *
     * Refusal-to-operate check (line 289):
     *   If the bundle has capabilityEvolutionAllowed: true AND the pack
     *   binding includes a strict pack AND the attestation workflow is NOT
     *   enabled, throws CapabilityEvolutionWithoutAttestationWorkflowError
     *   regardless of whether the hash matches.
     *
     * @throws EmptyPackBindingError if packBinding is empty.
     * @throws CapabilityEvolutionWithoutAttestationWorkflowError (line 289).
     */
    checkCurrentCapability(orgId, agentId, currentBundle, packBinding) {
        this.assertNonEmptyPackBinding(packBinding, 'checkCurrentCapability');
        const key = this.stateKey(orgId, agentId);
        const state = this.getOrCreateState(key);
        // Line-289 refusal-to-operate: strict pack + evolution allowed + no workflow.
        if (currentBundle.capabilityEvolutionAllowed) {
            const strictPacks = packBinding.filter((id) => STRICT_PACK_IDS.has(id));
            if (strictPacks.length > 0 && !state.attestationWorkflowEnabled) {
                throw new CapabilityEvolutionWithoutAttestationWorkflowError({
                    orgId,
                    agentId,
                    strictPacks,
                });
            }
        }
        const currentHash = this.computeCapabilityHash(orgId, agentId, currentBundle);
        // No registered version yet -- treat as verified (cold start).
        if (state.history.length === 0) {
            return { status: 'verified', currentHash };
        }
        const latestEntry = state.history[state.history.length - 1];
        const latestRegisteredHash = latestEntry.hash;
        // Hash matches -- verified.
        if (currentHash === latestRegisteredHash) {
            return { status: 'verified', currentHash, latestRegisteredHash };
        }
        // Hash mismatch.
        if (state.attestationWorkflowEnabled) {
            // Pending attestation path.
            const approvalId = `cap_attest_${Date.now()}_${crypto.randomBytes(4).toString('hex')}`;
            state.suspended = false;
            state.pendingApprovalId = approvalId;
            this.emit({
                type: 'CAPABILITY_CHANGE_PENDING_ATTESTATION',
                severity: 'WARNING',
                orgId,
                agentId,
                packBinding,
                currentHash,
                latestRegisteredHash,
                approvalQueueId: approvalId,
                autonomyLevelOverride: 0,
            });
            return {
                status: 'pending-attestation',
                currentHash,
                latestRegisteredHash,
                approvalQueueId: approvalId,
            };
        }
        else {
            // Auto-suspension path.
            const suspendedReason = `Capability hash changed from '${latestRegisteredHash.slice(0, 16)}...' ` +
                `to '${currentHash.slice(0, 16)}...' without an enabled attestation workflow.`;
            state.suspended = true;
            state.suspendedReason = suspendedReason;
            state.pendingApprovalId = null;
            this.emit({
                type: 'CAPABILITY_CHANGE_AUTO_SUSPENDED',
                severity: 'ERROR',
                orgId,
                agentId,
                packBinding,
                currentHash,
                latestRegisteredHash,
                suspendedReason,
            });
            return { status: 'suspended', currentHash, latestRegisteredHash };
        }
    }
    // -------------------------------------------------------------------------
    // Public: guardPreCall
    // -------------------------------------------------------------------------
    /**
     * Runtime guard called before any tool invocation, LLM call, or retrieval.
     *
     * Throws AgentCapabilitySuspendedError if the agent is suspended.
     * All cycle gates (PR #12-#15, #18, #20, #23, #25, #27) should call this
     * and short-circuit on throw.
     *
     * @throws EmptyPackBindingError if packBinding is empty.
     * @throws AgentCapabilitySuspendedError if suspended.
     */
    guardPreCall(orgId, agentId, packBinding) {
        this.assertNonEmptyPackBinding(packBinding, 'guardPreCall');
        const key = this.stateKey(orgId, agentId);
        const state = this.agentStates.get(key);
        if (!state)
            return; // No state recorded -- pass through.
        if (state.suspended) {
            throw new AgentCapabilitySuspendedError({
                orgId,
                agentId,
                suspendedReason: state.suspendedReason ?? 'Unknown capability change',
            });
        }
    }
    // -------------------------------------------------------------------------
    // Public: getVersionHistory
    // -------------------------------------------------------------------------
    /**
     * Return the full capability version history for an agent.
     *
     * The returned array is a shallow copy (immutable from caller perspective).
     * Each entry is frozen.
     *
     * Validates the hash chain before returning; if broken, emits
     * CAPABILITY_HISTORY_TAMPERED and throws CapabilityHistoryTamperedError.
     *
     * @throws EmptyPackBindingError if packBinding is empty.
     * @throws CapabilityHistoryTamperedError if chain is broken.
     */
    getVersionHistory(orgId, agentId, packBinding) {
        this.assertNonEmptyPackBinding(packBinding, 'getVersionHistory');
        const key = this.stateKey(orgId, agentId);
        const state = this.agentStates.get(key);
        if (!state || state.history.length === 0)
            return [];
        // Validate chain integrity before returning.
        this.validateHistoryChain(orgId, agentId, state, packBinding);
        return state.history.map((e) => Object.freeze({ ...e }));
    }
    // -------------------------------------------------------------------------
    // Public: enableAttestationWorkflow (operator-only)
    // -------------------------------------------------------------------------
    /**
     * Enable the attestation workflow for an agent.
     *
     * When enabled: capability changes route to pending-attestation (degraded
     * Level 0) rather than immediate suspension. An operator must approve or
     * deny via respondToAttestation().
     *
     * Operator-only. Emits CAPABILITY_ATTESTATION_WORKFLOW_ENABLED at severity ERROR.
     *
     * @throws EmptyPackBindingError if packBinding is empty.
     * @throws CapabilityAttestationPermissionError if identity is not admin.
     */
    enableAttestationWorkflow(orgId, agentId, approverIdentity, packBinding) {
        this.assertNonEmptyPackBinding(packBinding, 'enableAttestationWorkflow');
        this.assertOperatorIdentity(approverIdentity, 'enableAttestationWorkflow');
        const key = this.stateKey(orgId, agentId);
        const state = this.getOrCreateState(key);
        state.attestationWorkflowEnabled = true;
        this.emit({
            type: 'CAPABILITY_ATTESTATION_WORKFLOW_ENABLED',
            severity: 'ERROR',
            orgId,
            agentId,
            packBinding,
            approverIdentity,
        });
    }
    // -------------------------------------------------------------------------
    // Public: respondToAttestation (operator-only)
    // -------------------------------------------------------------------------
    /**
     * Resolve a pending capability change attestation.
     *
     * approve: registers the new bundle as a new version; clears suspended/pending
     *   state; emits CAPABILITY_ATTESTATION_APPROVED at severity ERROR.
     * deny: agent stays suspended; emits CAPABILITY_ATTESTATION_DENIED at
     *   severity ERROR. Operator must later register an older or corrected bundle.
     *
     * @throws EmptyPackBindingError if packBinding is empty.
     * @throws CapabilityAttestationPermissionError if identity is not admin.
     */
    respondToAttestation(approvalId, approverIdentity, decision, signedAttestation, packBinding, 
    /**
     * When decision is 'approve', the caller must supply the new bundle
     * and the orgId/agentId so it can be registered as a new version.
     */
    approveContext) {
        this.assertNonEmptyPackBinding(packBinding, 'respondToAttestation');
        this.assertOperatorIdentity(approverIdentity, 'respondToAttestation');
        if (!signedAttestation || signedAttestation.trim() === '') {
            throw new CapabilityAttestationPermissionError(approverIdentity, 'signedAttestation must be a non-empty string');
        }
        if (decision === 'approve') {
            if (!approveContext) {
                throw new Error('respondToAttestation: approveContext (orgId, agentId, newBundle) is required when decision is approve.');
            }
            const { orgId, agentId, newBundle } = approveContext;
            const key = this.stateKey(orgId, agentId);
            const state = this.getOrCreateState(key);
            // Register the approved bundle as a new version.
            const hash = this.computeCapabilityHash(orgId, agentId, newBundle);
            const prevEntry = state.history[state.history.length - 1] ?? null;
            const prevEntryHash = prevEntry
                ? this.hashVersionEntry(prevEntry)
                : HISTORY_GENESIS_HASH;
            const entry = {
                version: state.history.length + 1,
                hash,
                prevEntryHash,
                registeredAt: new Date().toISOString(),
                attesterIdentity: approverIdentity,
                attestationReason: `Approved attestation for approval ${approvalId}: ${signedAttestation}`,
                bundleSnapshot: this.snapshotBundle(newBundle),
            };
            state.history.push(entry);
            state.suspended = false;
            state.suspendedReason = null;
            state.pendingApprovalId = null;
            this.emit({
                type: 'CAPABILITY_ATTESTATION_APPROVED',
                severity: 'ERROR',
                orgId,
                agentId,
                packBinding,
                approvalId,
                approverIdentity,
                newVersion: entry.version,
                newHash: hash,
                signedAttestation,
            });
        }
        else {
            // deny -- agent stays suspended; find the org/agentId from any state
            // that has this pending approval ID.
            let found = false;
            for (const [key, state] of this.agentStates) {
                if (state.pendingApprovalId === approvalId) {
                    const [orgId, agentId] = this.parseStateKey(key);
                    state.suspended = true;
                    state.suspendedReason = `Attestation denied by '${approverIdentity}' for approval '${approvalId}'.`;
                    state.pendingApprovalId = null;
                    found = true;
                    this.emit({
                        type: 'CAPABILITY_ATTESTATION_DENIED',
                        severity: 'ERROR',
                        orgId,
                        agentId,
                        packBinding,
                        approvalId,
                        approverIdentity,
                        signedAttestation,
                    });
                    break;
                }
            }
            if (!found) {
                // Approval ID not found in pending state -- still emit the denial.
                this.emit({
                    type: 'CAPABILITY_ATTESTATION_DENIED',
                    severity: 'ERROR',
                    orgId: 'unknown',
                    agentId: 'unknown',
                    packBinding,
                    approvalId,
                    approverIdentity,
                    signedAttestation,
                    note: 'approval ID not found in active pending state',
                });
            }
        }
    }
    // -------------------------------------------------------------------------
    // Private helpers
    // -------------------------------------------------------------------------
    stateKey(orgId, agentId) {
        return `${orgId}::${agentId}`;
    }
    parseStateKey(key) {
        const idx = key.indexOf('::');
        return [key.slice(0, idx), key.slice(idx + 2)];
    }
    getOrCreateState(key) {
        let state = this.agentStates.get(key);
        if (!state) {
            state = {
                history: [],
                attestationWorkflowEnabled: false,
                suspended: false,
                suspendedReason: null,
                pendingApprovalId: null,
            };
            this.agentStates.set(key, state);
        }
        return state;
    }
    /**
     * Compute a stable hash over a CapabilityVersionEntry for chain integrity.
     * Excludes prevEntryHash itself to avoid circularity.
     */
    hashVersionEntry(entry) {
        const canonical = {
            version: entry.version,
            hash: entry.hash,
            registeredAt: entry.registeredAt,
            attesterIdentity: entry.attesterIdentity,
            attestationReason: entry.attestationReason,
        };
        return crypto.createHash('sha256').update(JSON.stringify(canonical)).digest('hex');
    }
    /**
     * Validate the hash chain of a history array.
     * Emits CAPABILITY_HISTORY_TAMPERED and throws if the chain is broken.
     */
    validateHistoryChain(orgId, agentId, state, packBinding) {
        for (let i = 1; i < state.history.length; i++) {
            const prev = state.history[i - 1];
            const curr = state.history[i];
            const expectedPrevHash = this.hashVersionEntry(prev);
            if (curr.prevEntryHash !== expectedPrevHash) {
                this.emit({
                    type: 'CAPABILITY_HISTORY_TAMPERED',
                    severity: 'ERROR',
                    orgId,
                    agentId,
                    packBinding,
                    brokenAtVersion: curr.version,
                    expectedPrevHash,
                    actualPrevHash: curr.prevEntryHash,
                });
                throw new CapabilityHistoryTamperedError({
                    orgId,
                    agentId,
                    brokenAtVersion: curr.version,
                });
            }
        }
        // Validate genesis link for the first entry.
        if (state.history.length > 0) {
            const first = state.history[0];
            if (first.prevEntryHash !== HISTORY_GENESIS_HASH) {
                this.emit({
                    type: 'CAPABILITY_HISTORY_TAMPERED',
                    severity: 'ERROR',
                    orgId,
                    agentId,
                    packBinding,
                    brokenAtVersion: 1,
                    expectedPrevHash: HISTORY_GENESIS_HASH,
                    actualPrevHash: first.prevEntryHash,
                });
                throw new CapabilityHistoryTamperedError({
                    orgId,
                    agentId,
                    brokenAtVersion: 1,
                });
            }
        }
    }
    /**
     * Assert pack binding is non-empty.
     */
    assertNonEmptyPackBinding(packBinding, operation) {
        if (!packBinding || packBinding.length === 0) {
            throw new EmptyPackBindingError(operation);
        }
    }
    /**
     * Assert that the caller is an operator (not agent runtime).
     *
     * Rejects identities with 'agent:' prefix (PT-CAPABILITY-3).
     * Verifies governance.configure permission via the injected checker if provided.
     */
    assertOperatorIdentity(identity, operation) {
        if (!identity || identity.trim() === '') {
            throw new CapabilityAttestationPermissionError(identity, 'identity must be non-empty');
        }
        // PT-CAPABILITY-3: reject agent runtime identity prefix.
        if (identity.startsWith('agent:')) {
            throw new CapabilityAttestationPermissionError(identity, `agent runtime identities (prefix 'agent:') cannot perform operator-only ` +
                `capability attestation operations. Use a human operator identity.`);
        }
        // Use injected permission checker if available.
        if (this.checkPermission) {
            const result = this.checkPermission(identity, 'governance.configure');
            if (!result.allowed) {
                throw new CapabilityAttestationPermissionError(identity, result.reason);
            }
        }
    }
    /**
     * Create an immutable snapshot of a bundle.
     */
    snapshotBundle(bundle) {
        return Object.freeze({
            toolset: Object.freeze([...bundle.toolset]),
            permissions: Object.freeze([...bundle.permissions]),
            webAccessTier: bundle.webAccessTier,
            hookProfile: bundle.hookProfile,
            autonomyLevel: bundle.autonomyLevel,
            packBindings: Object.freeze([...bundle.packBindings]),
            capabilityEvolutionAllowed: bundle.capabilityEvolutionAllowed,
        });
    }
    /**
     * Emit an audit event with SHA-256 chaining.
     */
    emit(data) {
        const event = {
            ...data,
            timestamp: new Date().toISOString(),
            prevSha: this.lastSha || undefined,
        };
        // Advance the chain.
        this.lastSha = crypto
            .createHash('sha256')
            .update(JSON.stringify(event))
            .digest('hex');
        try {
            this.onAudit(event);
        }
        catch {
            // Audit sink errors must not propagate -- governance must not block operation.
        }
    }
    /** Expose genesis hash for test introspection. */
    static get historyGenesisHash() {
        return HISTORY_GENESIS_HASH;
    }
}
//# sourceMappingURL=capability-change-detector.js.map