{"version":3,"file":"escalation.d.ts","sourceRoot":"","sources":["../../../../src/core/long-horizon/adaptive/escalation.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEhE,MAAM,MAAM,oBAAoB,GAC7B,qBAAqB,GACrB,yBAAyB,GACzB,6BAA6B,GAC7B,wBAAwB,GACxB,kCAAkC,GAClC,iCAAiC,CAAC;AAErC,iDAAiD;AACjD,eAAO,MAAM,4BAA4B,EAAE,aAAa,CAAC,oBAAoB,GAAG,MAAM,CAMrF,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAChC,mBAAmB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IACjC,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,2BAA2B,EAAE,MAAM,CAAC;IACpC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG,EAAE,iBAAiB,GAAG,kBAAkB,CAwCzG","sourcesContent":["/**\n * Bounded model escalation.\n *\n * Escalation is a separate, bounded decision from a strategy pivot. It moves\n * the same task to a stronger/compatible model for reasons such as a required\n * capability, repeated schema failure, independent review, or a high-risk\n * release gate. Escalation REQUIRES structured evidence and policy permission.\n * A model can recommend escalation but can never authorize it.\n */\n\nimport type { EscalationRequest, StallState } from \"./types.js\";\n\nexport type EscalationReasonCode =\n\t| \"capability_mismatch\"\n\t| \"repeated_schema_failure\"\n\t| \"independent_review_required\"\n\t| \"high_risk_release_gate\"\n\t| \"complex_cross_repository_failure\"\n\t| \"stall_after_distinct_strategies\";\n\n/** Reasons that are forbidden for escalation. */\nexport const FORBIDDEN_ESCALATION_REASONS: ReadonlyArray<EscalationReasonCode | string> = [\n\t\"model_requested_more_expensive\",\n\t\"more_tokens_might_help\",\n\t\"unspecified_difficulty\",\n\t\"user_authorization_missing\",\n\t\"policy_denied\",\n];\n\nexport interface EscalationBudget {\n\tmaxModelEscalations: number;\n}\n\nexport interface EscalationContext {\n\tusedEscalations: number;\n\tmaxModelEscalations: number;\n\tpolicyAllows: boolean;\n\tremainingBudget: number;\n\tstall?: StallState;\n\tfailureEvidenceCount: number;\n\tdistinctStrategiesAttempted: number;\n\tforcedReasons?: string[];\n}\n\nexport interface EscalationDecision {\n\tallowed: boolean;\n\treasonCodes: string[];\n\tblockedCodes: string[];\n\ttoProvider?: string;\n\ttoModel?: string;\n}\n\n/**\n * Evaluate an escalation request against policy and evidence. An escalation is\n * allowed only if: escalation budget remains, policy permits, allowed reasons\n * are present, and the aliasing of two equivalent models is not requested.\n */\nexport function evaluateEscalation(request: EscalationRequest, ctx: EscalationContext): EscalationDecision {\n\tconst blockedCodes: string[] = [];\n\tconst reasonCodes: string[] = [];\n\n\tif (request.fromProvider === request.toProvider && request.fromModel === request.toModel) {\n\t\tblockedCodes.push(\"ESCALATION_NOOP\");\n\t}\n\n\tfor (const reason of request.reasonCodes) {\n\t\tif (FORBIDDEN_ESCALATION_REASONS.includes(reason)) {\n\t\t\tblockedCodes.push(`FORBIDDEN_REASON:${reason}`);\n\t\t} else {\n\t\t\treasonCodes.push(reason);\n\t\t}\n\t}\n\n\tif (ctx.usedEscalations >= ctx.maxModelEscalations) {\n\t\tblockedCodes.push(\"ESCALATION_BUDGET_EXHAUSTED\");\n\t}\n\tif (!ctx.policyAllows) {\n\t\tblockedCodes.push(\"POLICY_DENIED\");\n\t}\n\tif (ctx.remainingBudget <= 0) {\n\t\tblockedCodes.push(\"NO_BUDGET\");\n\t}\n\n\t// Evidence-based reasons must be backed by structured evidence.\n\tconst evidenceBacked = validateEvidence(request.reasonCodes as EscalationReasonCode[], ctx);\n\tif (!evidenceBacked) {\n\t\tblockedCodes.push(\"ESCALATION_LACKS_EVIDENCE\");\n\t}\n\n\tconst allowed = blockedCodes.length === 0 && reasonCodes.length > 0;\n\treturn {\n\t\tallowed,\n\t\treasonCodes,\n\t\tblockedCodes,\n\t\ttoProvider: allowed ? request.toProvider : undefined,\n\t\ttoModel: allowed ? request.toModel : undefined,\n\t};\n}\n\nfunction validateEvidence(reasons: string[], ctx: EscalationContext): boolean {\n\tif (reasons.includes(\"independent_review_required\")) return true;\n\tif (reasons.includes(\"high_risk_release_gate\")) return true;\n\tif (reasons.includes(\"capability_mismatch\")) return false; // requires explicit capability mismatch evidence\n\tif (reasons.includes(\"repeated_schema_failure\")) return ctx.failureEvidenceCount >= 2;\n\tif (reasons.includes(\"complex_cross_repository_failure\")) return ctx.failureEvidenceCount >= 2;\n\tif (reasons.includes(\"stall_after_distinct_strategies\")) return ctx.distinctStrategiesAttempted >= 2;\n\treturn false;\n}\n"]}