import {
  parseFindingSubject
} from "./chunk-FRI6RG3P.js";
import {
  validateAgentProfileCell
} from "./chunk-ABOIVNXL.js";
import {
  canonicalize
} from "./chunk-VSMTAMNK.js";
import {
  ValidationError
} from "./chunk-3BFEG2F6.js";

// src/analyst/steer-firewall.ts
var OBSERVABLE_KINDS = /* @__PURE__ */ new Set([
  "span",
  "event",
  "artifact"
]);
function isTraceObservable(finding) {
  return finding.evidence_refs.some((ref) => OBSERVABLE_KINDS.has(ref.kind));
}
function isJudgeVerdict(finding) {
  return finding.derived_from_judge === true;
}
function assertNoJudgeVerdict(findings, context = "steer") {
  const leaks = findings.filter(isJudgeVerdict);
  if (leaks.length > 0) {
    throw new Error(
      `${context}: a judge verdict cannot be admitted as steering input \u2014 that is the held-out judge leaking into the loop. Offending judge-derived findings: [${leaks.map((f) => f.finding_id).join(", ")}]. Steering consumes observations of behavior, never acceptance verdicts.`
    );
  }
  return findings;
}

// src/analyst/policy-edit.ts
import { createHash } from "crypto";
var POLICY_EDIT_AXES = [
  "carrier",
  "representation",
  "budget",
  "sampling",
  "output_contract",
  "tool_contract",
  "routing",
  "memory",
  "agent_profile",
  "deployment_target"
];
var POLICY_EDIT_TARGET_SURFACES = [
  "prompt",
  "tool-contract",
  "runtime-config",
  "memory",
  "agent-profile",
  "deployment"
];
var PolicyEditValidationError = class extends ValidationError {
  path;
  constructor(message, path = "") {
    super(path ? `${message} (at ${path})` : message);
    this.path = path;
  }
};
var DEFAULT_MIN_SCORE = 0.7;
var DEFAULT_MIN_EXPECTED_GAIN = 0.01;
var POLICY_EDIT_ID = /^policy-edit:sha256:[0-9a-f]{64}$/;
function makePolicyEdit(init) {
  const normalized = normalizePolicyEdit({
    schemaVersion: "policy-edit/v1",
    ...init,
    source: normalizeSource(init.source)
  });
  const edit = {
    ...normalized,
    editId: init.editId ?? computePolicyEditId(normalized)
  };
  return validatePolicyEdit(edit);
}
function computePolicyEditId(edit) {
  const { editId: _editId, schemaVersion, ...material } = edit;
  void _editId;
  const canonical = JSON.stringify(canonicalize({ schemaVersion, ...material }));
  return `policy-edit:sha256:${createHash("sha256").update(canonical).digest("hex")}`;
}
function validatePolicyEdit(input) {
  if (input === null || typeof input !== "object") {
    throw new PolicyEditValidationError("expected object");
  }
  const obj = input;
  expectLiteral(obj.schemaVersion, "policy-edit/v1", "schemaVersion");
  expectString(obj.editId, "editId");
  if (!POLICY_EDIT_ID.test(obj.editId)) {
    throw new PolicyEditValidationError(
      "editId must match policy-edit:sha256:<64 lowercase hex chars>",
      "editId"
    );
  }
  expectOneOf(obj.axis, POLICY_EDIT_AXES, "axis");
  validateTarget(obj.target);
  validateChange(obj.change);
  expectString(obj.claim, "claim");
  validateExpectedGain(obj.expectedGain);
  expectConfidence(obj.confidence, "confidence");
  expectOneOf(obj.risk, ["low", "medium", "high", "unknown"], "risk");
  validateSource(obj.source);
  if (obj.rationale !== void 0) expectString(obj.rationale, "rationale");
  if (obj.validationPlan !== void 0) expectString(obj.validationPlan, "validationPlan");
  if (obj.metadata !== void 0 && (obj.metadata === null || typeof obj.metadata !== "object")) {
    throw new PolicyEditValidationError("expected object", "metadata");
  }
  const expectedId = computePolicyEditId(obj);
  if (obj.editId !== expectedId) {
    throw new PolicyEditValidationError("editId does not match policy edit content", "editId");
  }
  return obj;
}
function isPolicyEdit(input) {
  try {
    validatePolicyEdit(input);
    return true;
  } catch {
    return false;
  }
}
function policyEditsFromFindings(findings, opts = {}) {
  assertNoJudgeVerdict(findings, "policyEditsFromFindings");
  const edits = [];
  for (const finding of findings) {
    const edit = policyEditFromFinding(finding, opts);
    if (edit) edits.push(edit);
  }
  return edits;
}
function policyEditFromFinding(finding, opts = {}) {
  assertNoJudgeVerdict([finding], "policyEditFromFinding");
  if (!finding.recommended_action?.trim()) return null;
  const expectedGain = resolveExpectedGain(finding, opts);
  if (!expectedGain) return null;
  const routed = routeFindingSubject(finding.subject, opts);
  const risk = resolveRisk(finding, opts);
  return makePolicyEdit({
    axis: routed.axis,
    target: routed.target,
    change: { kind: "text", mode: "append", value: finding.recommended_action.trim() },
    claim: finding.claim,
    rationale: finding.rationale,
    expectedGain,
    confidence: finding.confidence,
    risk,
    validationPlan: finding.validation_plan,
    source: {
      findingIds: [finding.finding_id],
      analystIds: [finding.analyst_id],
      evidenceRefs: finding.evidence_refs,
      derivedFromJudge: finding.derived_from_judge
    }
  });
}
function scorePolicyEditReadiness(edit, opts = {}) {
  validatePolicyEdit(edit);
  const minExpectedGain = opts.minExpectedGain ?? DEFAULT_MIN_EXPECTED_GAIN;
  const evidenceScore = Math.min(1, edit.source.evidenceRefs.length / 2);
  const confidenceScore = clamp01(edit.confidence);
  const gainScore = clamp01(
    Math.abs(edit.expectedGain.amount) / Math.max(minExpectedGain * 5, 1e-3)
  );
  const targetScore = targetSpecificityScore(edit);
  const riskPenalty = edit.risk === "high" && opts.allowHighRisk !== true ? 0.35 : edit.risk === "unknown" ? 0.2 : 0;
  return clamp01(
    0.3 * evidenceScore + 0.25 * confidenceScore + 0.25 * gainScore + 0.2 * targetScore - riskPenalty
  );
}
function admitPolicyEdit(edit, opts = {}) {
  const validated = validatePolicyEdit(edit);
  const score = scorePolicyEditReadiness(validated, opts);
  const reasons = [];
  const minExpectedGain = opts.minExpectedGain ?? DEFAULT_MIN_EXPECTED_GAIN;
  const requireEvidence = opts.requireEvidence ?? true;
  if (validated.source.derivedFromJudge) {
    reasons.push("source is judge-derived; judge verdicts cannot steer policy edits");
  }
  if (requireEvidence && validated.source.evidenceRefs.length === 0) {
    reasons.push("missing evidence refs");
  }
  if (Math.abs(validated.expectedGain.amount) < minExpectedGain) {
    reasons.push(`expected gain below ${minExpectedGain}`);
  }
  if (validated.risk === "high" && opts.allowHighRisk !== true) {
    reasons.push("high-risk edit requires explicit allowHighRisk");
  }
  if (score < (opts.minScore ?? DEFAULT_MIN_SCORE)) {
    reasons.push(
      `readiness score ${score.toFixed(3)} below ${(opts.minScore ?? DEFAULT_MIN_SCORE).toFixed(3)}`
    );
  }
  return {
    edit: validated,
    decision: reasons.length === 0 ? "admit" : "reject",
    score,
    reasons
  };
}
function applyPolicyEditToSurface(surface, edit) {
  const validated = validatePolicyEdit(edit);
  if (validated.change.kind === "text") return applyTextChange(surface, validated.change);
  return applyJsonChange(surface, validated.change);
}
function routeFindingSubject(subject, opts) {
  const parsed = parseFindingSubject(subject);
  if (!parsed) {
    return {
      axis: opts.defaultAxis ?? "representation",
      target: { surface: opts.defaultTargetSurface ?? "prompt" }
    };
  }
  return routeParsedSubject(parsed);
}
function routeParsedSubject(subject) {
  switch (subject.kind) {
    case "system-prompt":
      return {
        axis: "representation",
        target: { surface: "prompt", path: `system-prompt:${subject.section}` }
      };
    case "tool-doc":
      return {
        axis: "tool_contract",
        target: {
          surface: "tool-contract",
          path: subject.aspect ? `tool-doc:${subject.tool}:${subject.aspect}` : `tool-doc:${subject.tool}`
        }
      };
    case "new-tool":
      return {
        axis: "tool_contract",
        target: { surface: "tool-contract", path: `new-tool:${subject.name}` }
      };
    case "rag":
      return {
        axis: "memory",
        target: { surface: "memory", path: `rag:${subject.corpus}:${subject.docId}` }
      };
    case "memory":
      return { axis: "memory", target: { surface: "memory", path: `memory:${subject.key}` } };
    case "scaffolding":
      return {
        axis: "routing",
        target: { surface: "runtime-config", path: `scaffolding:${subject.concern}` }
      };
    case "output-schema":
      return {
        axis: "output_contract",
        target: { surface: "runtime-config", path: `output-schema:${subject.field}` }
      };
    case "knowledge.wiki":
      return {
        axis: "memory",
        target: {
          surface: "memory",
          path: `agent-knowledge:wiki:${subject.slug}${subject.heading ? `#${subject.heading}` : ""}`
        }
      };
    case "knowledge.claim":
      return {
        axis: "memory",
        target: { surface: "memory", path: `agent-knowledge:claim:${subject.topic}` }
      };
    case "knowledge.raw":
      return {
        axis: "memory",
        target: { surface: "memory", path: `agent-knowledge:raw:${subject.sourceId}` }
      };
    case "knowledge.stale":
      return {
        axis: "memory",
        target: { surface: "memory", path: `agent-knowledge:stale:${subject.slug}` }
      };
    case "websearch.outdated":
      return {
        axis: "memory",
        target: { surface: "memory", path: `websearch:outdated:${subject.topic}` }
      };
    case "prior-run-summary":
      return {
        axis: "memory",
        target: { surface: "memory", path: `prior-run-summary:${subject.topic}` }
      };
    case "cluster":
      return { axis: "representation", target: { surface: "prompt", path: subject.label } };
  }
}
function resolveExpectedGain(finding, opts) {
  if (typeof opts.expectedGain === "function") return opts.expectedGain(finding) ?? null;
  if (opts.expectedGain) return opts.expectedGain;
  return readExpectedGainFromMetadata(finding.metadata);
}
function readExpectedGainFromMetadata(metadata) {
  const raw = readPolicyEditMetadata(metadata)?.expectedGain ?? readPolicyEditMetadata(metadata)?.expected_gain;
  if (!raw || typeof raw !== "object") return null;
  const obj = raw;
  if (typeof obj.metric !== "string" || obj.direction !== "increase" && obj.direction !== "decrease" || typeof obj.amount !== "number") {
    return null;
  }
  const out = {
    metric: obj.metric,
    direction: obj.direction,
    amount: obj.amount
  };
  if (obj.unit === "absolute" || obj.unit === "relative" || obj.unit === "percent" || obj.unit === "score") {
    out.unit = obj.unit;
  }
  if (typeof obj.rationale === "string") out.rationale = obj.rationale;
  return out;
}
function readPolicyEditMetadata(metadata) {
  const raw = metadata?.policyEdit ?? metadata?.policy_edit;
  return raw && typeof raw === "object" ? raw : null;
}
function resolveRisk(finding, opts) {
  if (typeof opts.risk === "function") return opts.risk(finding);
  if (opts.risk) return opts.risk;
  const raw = readPolicyEditMetadata(finding.metadata)?.risk;
  if (raw === "low" || raw === "medium" || raw === "high" || raw === "unknown") return raw;
  if (finding.severity === "critical" || finding.severity === "high") return "medium";
  return "low";
}
function applyTextChange(surface, change) {
  if (typeof surface !== "string") {
    throw new PolicyEditValidationError("text policy edits require a string surface", "change");
  }
  if (change.mode === "append") {
    if (hasExactTextBlock(surface, change.value)) return surface;
    return `${surface.trimEnd()}

${change.value}`.trimStart();
  }
  if (change.mode === "prepend") {
    if (hasExactTextBlock(surface, change.value)) return surface;
    return `${change.value}

${surface.trimStart()}`.trimEnd();
  }
  const find = expectNonEmpty(change.find, "change.find");
  if (!surface.includes(find)) {
    throw new PolicyEditValidationError("replace target not found in surface", "change.find");
  }
  return surface.replace(find, change.value);
}
function applyJsonChange(surface, change) {
  const root = parseJsonSurface(surface);
  const path = splitPath(change.path);
  if (change.mode === "remove") return setJsonAtPath(root, path, void 0, "remove");
  if (change.mode === "set") return setJsonAtPath(root, path, change.value ?? null, "set");
  const prior = readJsonAtPath(root, path);
  const merged = prior && typeof prior === "object" && !Array.isArray(prior) && change.value && typeof change.value === "object" && !Array.isArray(change.value) ? { ...prior, ...change.value } : change.value ?? null;
  return setJsonAtPath(root, path, merged, "set");
}
function parseJsonSurface(surface) {
  if (typeof surface === "string") {
    try {
      return JSON.parse(surface);
    } catch {
      throw new PolicyEditValidationError(
        "json policy edits require a JSON string surface",
        "change"
      );
    }
  }
  assertJson(surface, "surface");
  return surface;
}
function readJsonAtPath(root, path) {
  let cursor = root;
  for (const part of path) {
    if (!cursor || typeof cursor !== "object" || Array.isArray(cursor)) return void 0;
    cursor = cursor[part];
  }
  return cursor;
}
function setJsonAtPath(root, path, value, mode) {
  if (path.length === 0) {
    if (mode === "remove") return null;
    return value ?? null;
  }
  if (root === null || typeof root !== "object" || Array.isArray(root)) {
    throw new PolicyEditValidationError("json edit root must be an object", "change.path");
  }
  const out = { ...root };
  let cursor = out;
  for (let i = 0; i < path.length - 1; i++) {
    const key = path[i];
    const existing = cursor[key];
    if (mode === "remove" && (!existing || typeof existing !== "object" || Array.isArray(existing))) {
      return out;
    }
    const next = existing && typeof existing === "object" && !Array.isArray(existing) ? { ...existing } : {};
    cursor[key] = next;
    cursor = next;
  }
  const leaf = path[path.length - 1];
  if (mode === "remove") delete cursor[leaf];
  else cursor[leaf] = value ?? null;
  return out;
}
function normalizePolicyEdit(input) {
  const out = {
    schemaVersion: "policy-edit/v1",
    axis: input.axis,
    target: normalizeTarget(input.target),
    change: normalizeChange(input.change),
    claim: input.claim.trim(),
    expectedGain: normalizeExpectedGain(input.expectedGain),
    confidence: input.confidence,
    risk: input.risk,
    source: normalizeSource(input.source)
  };
  if (input.rationale?.trim()) out.rationale = input.rationale.trim();
  if (input.validationPlan?.trim()) out.validationPlan = input.validationPlan.trim();
  if (input.metadata) out.metadata = input.metadata;
  return out;
}
function normalizeTarget(target) {
  const out = { surface: target.surface };
  if (target.path?.trim()) out.path = target.path.trim();
  if (target.agentProfileCell)
    out.agentProfileCell = validateAgentProfileCell(target.agentProfileCell);
  if (target.label?.trim()) out.label = target.label.trim();
  return out;
}
function normalizeChange(change) {
  if (change.kind === "text") {
    const out2 = {
      kind: "text",
      mode: change.mode,
      value: change.value.trim()
    };
    if (change.find?.trim()) out2.find = change.find.trim();
    return out2;
  }
  const out = {
    kind: "json",
    mode: change.mode,
    path: change.path.trim()
  };
  if (change.value !== void 0) out.value = change.value;
  return out;
}
function normalizeExpectedGain(gain) {
  const out = {
    metric: gain.metric.trim(),
    direction: gain.direction,
    amount: gain.amount
  };
  if (gain.unit) out.unit = gain.unit;
  if (gain.rationale?.trim()) out.rationale = gain.rationale.trim();
  return out;
}
function normalizeSource(source) {
  const out = {
    findingIds: uniqueSorted(source.findingIds.map((s) => s.trim()).filter(Boolean)),
    analystIds: uniqueSorted(source.analystIds.map((s) => s.trim()).filter(Boolean)),
    evidenceRefs: source.evidenceRefs
  };
  if (source.derivedFromJudge) out.derivedFromJudge = true;
  return out;
}
function validateTarget(target) {
  if (!target || typeof target !== "object")
    throw new PolicyEditValidationError("expected object", "target");
  const obj = target;
  expectOneOf(obj.surface, POLICY_EDIT_TARGET_SURFACES, "target.surface");
  if (obj.path !== void 0) expectString(obj.path, "target.path");
  if (obj.label !== void 0) expectString(obj.label, "target.label");
  if (obj.agentProfileCell !== void 0) validateAgentProfileCell(obj.agentProfileCell);
}
function validateChange(change) {
  if (!change || typeof change !== "object")
    throw new PolicyEditValidationError("expected object", "change");
  const obj = change;
  if (obj.kind !== "text" && obj.kind !== "json") {
    throw new PolicyEditValidationError("kind must be text or json", "change.kind");
  }
  if (obj.kind === "text") {
    expectOneOf(obj.mode, ["append", "prepend", "replace"], "change.mode");
    expectString(obj.value, "change.value");
    if (obj.mode === "replace") expectString(obj.find, "change.find");
    return;
  }
  expectOneOf(obj.mode, ["set", "merge", "remove"], "change.mode");
  expectString(obj.path, "change.path");
  if (obj.value !== void 0) assertJson(obj.value, "change.value");
}
function validateExpectedGain(gain) {
  if (!gain || typeof gain !== "object")
    throw new PolicyEditValidationError("expected object", "expectedGain");
  const obj = gain;
  expectString(obj.metric, "expectedGain.metric");
  expectOneOf(obj.direction, ["increase", "decrease"], "expectedGain.direction");
  if (!Number.isFinite(obj.amount) || obj.amount <= 0) {
    throw new PolicyEditValidationError(
      "amount must be a positive finite number",
      "expectedGain.amount"
    );
  }
  if (obj.unit !== void 0) {
    expectOneOf(
      obj.unit,
      ["absolute", "relative", "percent", "score"],
      "expectedGain.unit"
    );
  }
  if (obj.rationale !== void 0) expectString(obj.rationale, "expectedGain.rationale");
}
function validateSource(source) {
  if (!source || typeof source !== "object")
    throw new PolicyEditValidationError("expected object", "source");
  const obj = source;
  expectNonEmptyStringArray(obj.findingIds, "source.findingIds");
  expectNonEmptyStringArray(obj.analystIds, "source.analystIds");
  if (!Array.isArray(obj.evidenceRefs)) {
    throw new PolicyEditValidationError("expected array", "source.evidenceRefs");
  }
  for (const [i, ref] of obj.evidenceRefs.entries())
    validateEvidenceRef(ref, `source.evidenceRefs.${i}`);
  if (obj.derivedFromJudge !== void 0 && typeof obj.derivedFromJudge !== "boolean") {
    throw new PolicyEditValidationError("expected boolean", "source.derivedFromJudge");
  }
}
function validateEvidenceRef(ref, path) {
  if (!ref || typeof ref !== "object") throw new PolicyEditValidationError("expected object", path);
  const obj = ref;
  expectOneOf(obj.kind, ["span", "event", "artifact", "finding", "metric"], `${path}.kind`);
  expectString(obj.uri, `${path}.uri`);
  if (obj.excerpt !== void 0) expectString(obj.excerpt, `${path}.excerpt`);
}
function assertJson(value, path) {
  if (value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value)) {
    return;
  }
  if (Array.isArray(value)) {
    for (const [i, item] of value.entries()) assertJson(item, `${path}.${i}`);
    return;
  }
  if (typeof value === "object") {
    for (const [key, item] of Object.entries(value)) {
      if (!key) throw new PolicyEditValidationError("empty object key", path);
      assertJson(item, `${path}.${key}`);
    }
    return;
  }
  throw new PolicyEditValidationError("expected JSON-compatible value", path);
}
function targetSpecificityScore(edit) {
  let score = 0.4;
  if (edit.target.path) score += 0.25;
  if (edit.target.agentProfileCell) score += 0.15;
  if (edit.change.kind === "json" || edit.change.mode === "replace") score += 0.2;
  else if (edit.change.value.length > 0) score += 0.1;
  return clamp01(score);
}
function splitPath(path) {
  const parts = path.split(".").map((p) => p.trim()).filter(Boolean);
  if (parts.length === 0)
    throw new PolicyEditValidationError("path must not be empty", "change.path");
  return parts;
}
function expectLiteral(value, expected, path) {
  if (value !== expected) throw new PolicyEditValidationError(`expected ${expected}`, path);
}
function expectString(value, path) {
  if (typeof value !== "string" || value.trim().length === 0) {
    throw new PolicyEditValidationError("expected non-empty string", path);
  }
}
function expectNonEmpty(value, path) {
  expectString(value, path);
  return value;
}
function expectConfidence(value, path) {
  if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1) {
    throw new PolicyEditValidationError("expected finite number in [0,1]", path);
  }
}
function hasExactTextBlock(surface, value) {
  const needle = normalizeTextBlock(value);
  const normalizedSurface = surface.replace(/\r\n/g, "\n");
  return [...normalizedSurface.split(/\n{2,}/), ...normalizedSurface.split("\n")].some(
    (block) => normalizeTextBlock(block) === needle
  );
}
function normalizeTextBlock(value) {
  return value.replace(/\r\n/g, "\n").trim();
}
function expectOneOf(value, allowed, path) {
  if (typeof value !== "string" || !allowed.includes(value)) {
    throw new PolicyEditValidationError(`expected one of ${allowed.join(", ")}`, path);
  }
}
function expectStringArray(value, path) {
  if (!Array.isArray(value)) throw new PolicyEditValidationError("expected array", path);
  for (const [i, item] of value.entries()) expectString(item, `${path}.${i}`);
}
function expectNonEmptyStringArray(value, path) {
  expectStringArray(value, path);
  if (value.length === 0) throw new PolicyEditValidationError("expected non-empty array", path);
}
function uniqueSorted(values) {
  return [...new Set(values)].sort();
}
function clamp01(n) {
  if (!Number.isFinite(n)) return 0;
  if (n < 0) return 0;
  if (n > 1) return 1;
  return n;
}

// src/run-score.ts
var DEFAULT_RUN_SCORE_WEIGHTS = {
  success: 4,
  goalProgress: 2,
  repoGroundedness: 1.5,
  driftPenalty: -1.5,
  toolUseQuality: 1,
  patchQuality: 1.25,
  testReality: 1.5,
  finalGate: 3,
  reviewerBlockers: -2,
  costUsd: -0.2,
  wallSeconds: -0.1
};
function aggregateRunScore(score, weights = {}) {
  const w = { ...DEFAULT_RUN_SCORE_WEIGHTS, ...weights };
  return w.success * clamp012(score.success) + w.goalProgress * clamp012(score.goalProgress) + w.repoGroundedness * clamp012(score.repoGroundedness) + w.driftPenalty * clamp012(score.driftPenalty) + w.toolUseQuality * clamp012(score.toolUseQuality) + w.patchQuality * clamp012(score.patchQuality) + w.testReality * clamp012(score.testReality) + w.finalGate * clamp012(score.finalGate) + w.reviewerBlockers * clamp012(score.reviewerBlockers) + w.costUsd * Math.max(0, finiteOrZero(score.costUsd)) + w.wallSeconds * Math.max(0, finiteOrZero(score.wallSeconds) / 60);
}
function clamp012(value) {
  if (!Number.isFinite(value)) return 0;
  return Math.max(0, Math.min(1, value));
}
function finiteOrZero(value) {
  return Number.isFinite(value) ? value : 0;
}

export {
  isTraceObservable,
  isJudgeVerdict,
  assertNoJudgeVerdict,
  POLICY_EDIT_AXES,
  POLICY_EDIT_TARGET_SURFACES,
  PolicyEditValidationError,
  makePolicyEdit,
  computePolicyEditId,
  validatePolicyEdit,
  isPolicyEdit,
  policyEditsFromFindings,
  policyEditFromFinding,
  scorePolicyEditReadiness,
  admitPolicyEdit,
  applyPolicyEditToSurface,
  DEFAULT_RUN_SCORE_WEIGHTS,
  aggregateRunScore,
  clamp012 as clamp01
};
//# sourceMappingURL=chunk-IN3SHQML.js.map