import {
  clampInstructionHeavyTokenCap
} from "./chunk-6HZ6AO2P.js";
import {
  clamp01,
  clampLifecycleThreshold
} from "./chunk-TBBDFYXW.js";

// src/policy-runtime.ts
import path from "path";
import { mkdir, readFile, rename, writeFile } from "fs/promises";
var RUNTIME_POLICY_VERSION = 1;
var RUNTIME_POLICY_FILE = "policy-runtime.json";
var RUNTIME_POLICY_PREV_FILE = "policy-runtime.prev.json";
function sanitizeRuntimePolicyValues(values, options) {
  const out = {};
  if (typeof values.recencyWeight === "number") {
    out.recencyWeight = clamp01(values.recencyWeight);
  }
  if (typeof values.lifecyclePromoteHeatThreshold === "number") {
    out.lifecyclePromoteHeatThreshold = clampLifecycleThreshold(values.lifecyclePromoteHeatThreshold);
  }
  if (typeof values.lifecycleStaleDecayThreshold === "number") {
    const staleDecayThreshold = clampLifecycleThreshold(values.lifecycleStaleDecayThreshold);
    const maxStaleDecayThreshold = typeof options?.maxStaleDecayThreshold === "number" ? clampLifecycleThreshold(options.maxStaleDecayThreshold) : 1;
    out.lifecycleStaleDecayThreshold = Math.min(staleDecayThreshold, maxStaleDecayThreshold);
  }
  if (typeof values.cronRecallInstructionHeavyTokenCap === "number") {
    out.cronRecallInstructionHeavyTokenCap = clampInstructionHeavyTokenCap(
      values.cronRecallInstructionHeavyTokenCap
    );
  }
  return out;
}
function isRuntimeParameter(parameter) {
  return parameter === "recencyWeight" || parameter === "lifecyclePromoteHeatThreshold" || parameter === "lifecycleStaleDecayThreshold" || parameter === "cronRecallInstructionHeavyTokenCap";
}
async function readRuntimePolicySnapshot(filePath, options) {
  try {
    const raw = await readFile(filePath, "utf-8");
    const parsed = JSON.parse(raw);
    if (!parsed || typeof parsed.version !== "number" || parsed.version < 1 || typeof parsed.updatedAt !== "string" || !parsed.values || typeof parsed.values !== "object" || typeof parsed.sourceAdjustmentCount !== "number" || parsed.sourceAdjustmentCount < 0) {
      return null;
    }
    return {
      version: parsed.version,
      updatedAt: parsed.updatedAt,
      values: sanitizeRuntimePolicyValues(parsed.values, {
        maxStaleDecayThreshold: options?.maxStaleDecayThreshold
      }),
      sourceAdjustmentCount: parsed.sourceAdjustmentCount
    };
  } catch {
    return null;
  }
}
async function writeSnapshotAtomic(filePath, snapshot) {
  const tempPath = `${filePath}.tmp`;
  await mkdir(path.dirname(filePath), { recursive: true });
  await writeFile(tempPath, `${JSON.stringify(snapshot, null, 2)}
`, "utf-8");
  await rename(tempPath, filePath);
}
var PolicyRuntimeManager = class {
  constructor(memoryDir, config) {
    this.memoryDir = memoryDir;
    this.config = config;
    const stateDir = path.join(memoryDir, "state");
    this.runtimePath = path.join(stateDir, RUNTIME_POLICY_FILE);
    this.runtimePrevPath = path.join(stateDir, RUNTIME_POLICY_PREV_FILE);
  }
  memoryDir;
  config;
  runtimePath;
  runtimePrevPath;
  async loadRuntimeValues() {
    const snapshot = await readRuntimePolicySnapshot(this.runtimePath, {
      maxStaleDecayThreshold: this.config.lifecycleArchiveDecayThreshold
    });
    if (!snapshot) return null;
    return snapshot.values;
  }
  async rollback() {
    const previous = await readRuntimePolicySnapshot(this.runtimePrevPath, {
      maxStaleDecayThreshold: this.config.lifecycleArchiveDecayThreshold
    });
    if (!previous) return false;
    await writeSnapshotAtomic(this.runtimePath, {
      ...previous,
      updatedAt: (/* @__PURE__ */ new Date()).toISOString()
    });
    return true;
  }
  async applyFromBehaviorState(state) {
    const adjustmentCount = state.adjustments.length;
    if (adjustmentCount === 0) {
      return { applied: false, rolledBack: false, values: await this.loadRuntimeValues(), reason: "no_adjustments" };
    }
    const protectedSet = /* @__PURE__ */ new Set([
      ...this.config.behaviorLoopProtectedParams,
      ...state.protectedParams
    ]);
    const existing = await readRuntimePolicySnapshot(this.runtimePath, {
      maxStaleDecayThreshold: this.config.lifecycleArchiveDecayThreshold
    });
    const candidate = {
      recencyWeight: existing?.values.recencyWeight ?? this.config.recencyWeight,
      lifecyclePromoteHeatThreshold: existing?.values.lifecyclePromoteHeatThreshold ?? this.config.lifecyclePromoteHeatThreshold,
      lifecycleStaleDecayThreshold: existing?.values.lifecycleStaleDecayThreshold ?? this.config.lifecycleStaleDecayThreshold,
      cronRecallInstructionHeavyTokenCap: existing?.values.cronRecallInstructionHeavyTokenCap ?? this.config.cronRecallInstructionHeavyTokenCap
    };
    for (const adjustment of state.adjustments) {
      if (!isRuntimeParameter(adjustment.parameter)) {
        let rolledBack = false;
        if (existing) {
          await writeSnapshotAtomic(this.runtimePath, existing);
          rolledBack = true;
        } else {
          rolledBack = await this.rollback();
        }
        return {
          applied: false,
          rolledBack,
          values: await this.loadRuntimeValues(),
          reason: `invalid_parameter:${adjustment.parameter}`
        };
      }
      if (protectedSet.has(adjustment.parameter)) {
        continue;
      }
      if (!Number.isFinite(adjustment.nextValue)) {
        let rolledBack = false;
        if (existing) {
          await writeSnapshotAtomic(this.runtimePath, existing);
          rolledBack = true;
        } else {
          rolledBack = await this.rollback();
        }
        return {
          applied: false,
          rolledBack,
          values: await this.loadRuntimeValues(),
          reason: `invalid_value:${adjustment.parameter}`
        };
      }
      candidate[adjustment.parameter] = adjustment.nextValue;
    }
    const sanitized = sanitizeRuntimePolicyValues(candidate, {
      maxStaleDecayThreshold: this.config.lifecycleArchiveDecayThreshold
    });
    if (existing) {
      await writeSnapshotAtomic(this.runtimePrevPath, existing);
    }
    const nextSnapshot = {
      version: RUNTIME_POLICY_VERSION,
      updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
      values: sanitized,
      sourceAdjustmentCount: adjustmentCount
    };
    await writeSnapshotAtomic(this.runtimePath, nextSnapshot);
    return { applied: true, rolledBack: false, values: sanitized, reason: "applied" };
  }
};

export {
  sanitizeRuntimePolicyValues,
  readRuntimePolicySnapshot,
  PolicyRuntimeManager
};
//# sourceMappingURL=chunk-EABGC2TL.js.map