"use strict";
/**
 * PackEvaluator prewarm -- V8 JIT warmup before external traffic arrives.
 *
 * Problem: V8's Sparkplug/Maglev JIT compilers tier up only after a function
 * is called enough times to be considered "hot". On a cold server start, the
 * first 5-50 seconds of traffic at 10 RPS will see p99 90-130ms (exceeds the
 * 50ms GAP-S3-01 budget) while V8 compiles the PackEvaluator hot path.
 *
 * Solution: before server.listen() binds the external port, run one synthetic
 * evaluate() call per active pack. This drives:
 *   - getClassifierIndex() (cache miss path -> buildClassifierIndex -> Map ops)
 *   - categoryMatches() for each classifier
 *   - All downstream helper functions (serializeActionForMatching, actionToVerdict,
 *     stricterVerdict, buildReason)
 *
 * After prewarm completes, the JIT has promoted the hot path to Maglev tier.
 * Steady-state p99 drops to ~0.241ms (Wave A measurement).
 *
 * Boot-gate contract: if prewarm throws, the calling server MUST refuse to bind
 * the port. A prewarm failure indicates a broken pack registry (e.g., a pack with
 * malformed categoryActions that crashes the evaluator), which would cause runtime
 * governance failures later. Fail loud at boot rather than at the first user call.
 *
 * @connexum/ai-governance  Wave-B
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.prewarmPackEvaluator = prewarmPackEvaluator;
exports.createAndPrewarmEvaluator = createAndPrewarmEvaluator;
const pack_evaluator_1 = require("./pack-evaluator");
const event_bus_1 = require("../audit/event-bus");
const index_1 = require("../adapters/index");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
/**
 * Synthetic tenant ID used exclusively for prewarm calls.
 * Using a reserved prefix makes prewarm traffic easy to filter from audit logs.
 */
const PREWARM_TENANT_ID = '__prewarm__';
const PREWARM_AGENT_ID = '__prewarm__';
/**
 * Synthetic action context used for prewarm calls.
 * The toolName and args are chosen to be inert (no real governance action)
 * while still exercising the full evaluate() code path through the hot functions.
 */
const PREWARM_ACTION_CONTEXT = (0, index_1.createActionContext)('prewarm', { sample: 'prewarm-test-data' }, { name: PREWARM_AGENT_ID, orgId: PREWARM_TENANT_ID });
/**
 * Run one synthetic evaluate() call per active pack.
 *
 * @param packRegistry - The registry from which active packs are resolved.
 * @param evaluator    - The PackEvaluator instance to warm. Pass the same
 *                       instance that will serve production traffic so the
 *                       JIT warmup and cache state carry over.
 * @returns PrewarmResult with pack count and elapsed time.
 * @throws  If any pack's prewarm call throws (boot-gate: caller must not bind port).
 */
async function prewarmPackEvaluator(packRegistry, evaluator) {
    const activePacks = packRegistry.getActive();
    const t0 = Date.now();
    if (activePacks.length === 0) {
        // Empty registry: no-op. Not an error -- single-tenant installs without
        // packs still need to boot successfully.
        return { packCount: 0, elapsedMs: 0 };
    }
    // One evaluate() call per active pack. We use the pack's own tenant ID key
    // to ensure each pack's cache entry is seeded. In practice, multi-tenant
    // production tenants will use their own tenant IDs; the prewarm seeds the
    // JIT not the production cache. Flush the prewarm tenant entry afterward
    // so it doesn't interfere with production tenant cache entries.
    for (const pack of activePacks) {
        // Use the pack ID as the synthetic tenant key so each pack gets its own
        // cache entry built (exercises the full buildClassifierIndex path per pack).
        const syntheticTenantId = `${PREWARM_TENANT_ID}:${pack.id}`;
        // This call MUST NOT be swallowed: if evaluate() throws here, the pack
        // registry is broken and the boot-gate must refuse to start the server.
        evaluator.evaluate(syntheticTenantId, PREWARM_AGENT_ID, PREWARM_ACTION_CONTEXT);
        // Flush the prewarm tenant from cache: prewarm seeds the JIT, not the
        // production cache. Production tenants will get their own cold-start miss
        // which is now cheap because the JIT is warmed.
        evaluator.flushTenant(syntheticTenantId);
    }
    const elapsedMs = Date.now() - t0;
    return { packCount: activePacks.length, elapsedMs };
}
/**
 * Convenience factory: creates a fresh PackEvaluator, runs prewarm, then
 * returns the evaluator for production use. Useful when the caller does not
 * already have an evaluator instance.
 *
 * Boot-gate: throws if prewarm fails. Caller must not proceed to server.listen().
 */
async function createAndPrewarmEvaluator(packRegistry, options) {
    const ebDir = options?.eventBusDir ??
        fs.mkdtempSync(path.join(os.tmpdir(), 'ga-prewarm-'));
    const eventBus = new event_bus_1.EventBus({
        eventDir: ebDir,
        agentName: options?.agentName ?? 'governance-server',
    });
    const evaluator = new pack_evaluator_1.PackEvaluator(packRegistry, eventBus, {
        ttlMs: options?.ttlMs,
    });
    const prewarmResult = await prewarmPackEvaluator(packRegistry, evaluator);
    return { evaluator, prewarmResult };
}
//# sourceMappingURL=pack-evaluator-prewarm.js.map