{"version":3,"file":"rpc.d.ts","sourceRoot":"","sources":["../../../src/core/routing/rpc.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,eAAO,MAAM,mBAAmB,GAAa,CAAC;AAE9C,eAAO,MAAM,sBAAsB,sYAkBzB,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E,MAAM,WAAW,iBAAiB;IACjC,OAAO,EAAE,OAAO,mBAAmB,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,mBAAmB,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC5F;AAED,MAAM,MAAM,mBAAmB,GAAG,mBAAmB,GAAG,WAAW,GAAG,iBAAiB,GAAG,cAAc,CAAC;AAEzG,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,mBAAmB,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,aAAa,CAAgD;IAErE,OAAO,CAAC,QAAQ;IAOhB,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,kBAAkB,GAAG,eAAe,CAwIvE;CACD;AAED,MAAM,MAAM,kBAAkB,GAAG;IAAE,SAAS,EAAE,mBAAmB,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC","sourcesContent":["/**\n * Versioned routing RPC service.\n *\n * Operations are read-only projections or explicit-gated mutations. Promotion\n * requires an authorized RPC. All payloads are bounded and free of credentials.\n */\n\nimport { activePolicyContext, activePolicyStatus, fixtureEvidence } from \"./cli-helpers.js\";\nimport { checkDriftHealth, type DriftDimension, detectDrift } from \"./drift.js\";\nimport { decide, replayDecision } from \"./engine.js\";\nimport { extractFeatures } from \"./features.js\";\nimport { comparePolicies, promotePolicy, rollbackPolicy, validatePromotionGates } from \"./promotion.js\";\nimport { listDecisions, listPolicies, listShadowDecisions, readPolicy } from \"./store.js\";\nimport type { CandidateEvidence, OrchestrationCandidate } from \"./types.js\";\n\nexport const ROUTING_RPC_VERSION = 1 as const;\n\nexport const ROUTING_RPC_OPERATIONS = [\n\t\"routing.status\",\n\t\"routing.decide\",\n\t\"routing.explain\",\n\t\"routing.replay\",\n\t\"routing.compare\",\n\t\"routing.candidates\",\n\t\"routing.features\",\n\t\"routing.shadowStatus\",\n\t\"routing.shadowCompare\",\n\t\"routing.policyList\",\n\t\"routing.policyInspect\",\n\t\"routing.policyValidate\",\n\t\"routing.policyCompare\",\n\t\"routing.policyPromote\",\n\t\"routing.policyRollback\",\n\t\"routing.driftStatus\",\n\t\"routing.driftInspect\",\n] as const;\n\nexport type RoutingRpcOperation = (typeof ROUTING_RPC_OPERATIONS)[number];\n\nexport interface RoutingRpcRequest {\n\tversion: typeof ROUTING_RPC_VERSION;\n\trequestId: string;\n\toperation: RoutingRpcOperation;\n\tparameters?: Record<string, string | number | boolean | string[] | Record<string, unknown>>;\n}\n\nexport type RoutingRpcErrorKind = \"invalid_operation\" | \"not_found\" | \"invalid_request\" | \"unauthorized\";\n\nexport interface RoutingRpcError {\n\terror: RoutingRpcErrorKind;\n\tmessage: string;\n}\n\nexport class RoutingRpcService {\n\tprivate evidenceCache: Record<string, CandidateEvidence> | undefined;\n\n\tprivate evidence(): Record<string, CandidateEvidence> {\n\t\tif (!this.evidenceCache) {\n\t\t\tthis.evidenceCache = fixtureEvidence();\n\t\t}\n\t\treturn this.evidenceCache;\n\t}\n\n\thandle(request: RoutingRpcRequest): RoutingRpcResponse | RoutingRpcError {\n\t\tif (request.version !== ROUTING_RPC_VERSION) {\n\t\t\treturn { error: \"invalid_request\", message: `Unsupported routing RPC version ${request.version}` };\n\t\t}\n\t\tswitch (request.operation) {\n\t\t\tcase \"routing.status\":\n\t\t\t\treturn { operation: request.operation, data: routingStatusPayload() };\n\t\t\tcase \"routing.decide\": {\n\t\t\t\tconst task = String(request.parameters?.task ?? \"\");\n\t\t\t\tif (!task) return { error: \"invalid_request\", message: \"routing.decide requires task parameter\" };\n\t\t\t\tconst { decision, selectedCandidate } = decide({\n\t\t\t\t\ttask,\n\t\t\t\t\tevidence: this.evidence(),\n\t\t\t\t\tpolicyContext: activePolicyContext(),\n\t\t\t\t\toperatorOverride: request.parameters?.overrideCandidateId\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tauthorizedBy: \"rpc\",\n\t\t\t\t\t\t\t\tcandidateId: String(request.parameters.overrideCandidateId),\n\t\t\t\t\t\t\t\treason: \"operator override via RPC\",\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: undefined,\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\toperation: request.operation,\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tdecision,\n\t\t\t\t\t\tselectedCandidate: selectedCandidate ? summarizeCandidate(selectedCandidate) : undefined,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"routing.explain\": {\n\t\t\t\tconst id = String(request.parameters?.decisionId ?? \"\");\n\t\t\t\tconst d = replayDecision(id);\n\t\t\t\treturn d ? { operation: request.operation, data: { decision: d } } : notFound(id);\n\t\t\t}\n\t\t\tcase \"routing.replay\": {\n\t\t\t\tconst id = String(request.parameters?.decisionId ?? \"\");\n\t\t\t\tconst d = replayDecision(id);\n\t\t\t\treturn d ? { operation: request.operation, data: { replay: \"zero-effect\", decision: d } } : notFound(id);\n\t\t\t}\n\t\t\tcase \"routing.compare\": {\n\t\t\t\tconst a = replayDecision(String(request.parameters?.a ?? \"\"));\n\t\t\t\tconst b = replayDecision(String(request.parameters?.b ?? \"\"));\n\t\t\t\treturn { operation: request.operation, data: { left: a, right: b } };\n\t\t\t}\n\t\t\tcase \"routing.candidates\":\n\t\t\t\treturn {\n\t\t\t\t\toperation: request.operation,\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tcandidateSources: [\n\t\t\t\t\t\t\t\"provider-profiles\",\n\t\t\t\t\t\t\t\"model-registry\",\n\t\t\t\t\t\t\t\"subagent-registry\",\n\t\t\t\t\t\t\t\"skill-registry\",\n\t\t\t\t\t\t\t\"retrieval-policies\",\n\t\t\t\t\t\t\t\"budget-classes\",\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\tcase \"routing.features\": {\n\t\t\t\tconst task = String(request.parameters?.task ?? \"\");\n\t\t\t\treturn { operation: request.operation, data: { features: extractFeatures(task || \"sample task\") } };\n\t\t\t}\n\t\t\tcase \"routing.shadowStatus\":\n\t\t\t\treturn {\n\t\t\t\t\toperation: request.operation,\n\t\t\t\t\tdata: { shadowDecisions: listShadowDecisions(10), zeroEffects: true },\n\t\t\t\t};\n\t\t\tcase \"routing.shadowCompare\":\n\t\t\t\treturn { operation: request.operation, data: { shadowComparisons: listShadowDecisions(10) } };\n\t\t\tcase \"routing.policyList\":\n\t\t\t\treturn {\n\t\t\t\t\toperation: request.operation,\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tpolicies: listPolicies().map((p) => ({\n\t\t\t\t\t\t\tpolicyId: p.policyId,\n\t\t\t\t\t\t\tpolicyVersion: p.policyVersion,\n\t\t\t\t\t\t\tstatus: p.status,\n\t\t\t\t\t\t\tsourceDatasetHash: p.sourceDatasetHash,\n\t\t\t\t\t\t})),\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\tcase \"routing.policyInspect\": {\n\t\t\t\tconst p = readPolicy(String(request.parameters?.policyId ?? \"\"));\n\t\t\t\treturn p\n\t\t\t\t\t? { operation: request.operation, data: { policy: p } }\n\t\t\t\t\t: notFound(String(request.parameters?.policyId));\n\t\t\t}\n\t\t\tcase \"routing.policyValidate\": {\n\t\t\t\tconst p = readPolicy(String(request.parameters?.policyId ?? \"\"));\n\t\t\t\tif (!p) return notFound(String(request.parameters?.policyId));\n\t\t\t\tconst gate = validatePromotionGates(p, this.evidence(), {\n\t\t\t\t\tsafetyFloor: 0.5,\n\t\t\t\t\tcorrectnessFloor: 0.5,\n\t\t\t\t\tflakinessCeiling: 0.3,\n\t\t\t\t\trequiredScenarioPack: \"routing\",\n\t\t\t\t\toperatorAuthorized: true,\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\toperation: request.operation,\n\t\t\t\t\tdata: { policyId: p.policyId, valid: gate.passed, reasonCodes: gate.reasonCodes },\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"routing.policyCompare\": {\n\t\t\t\tconst a = readPolicy(String(request.parameters?.a ?? \"\"));\n\t\t\t\tconst b = readPolicy(String(request.parameters?.b ?? \"\"));\n\t\t\t\tif (!a || !b) return notFound(\"policy compare\");\n\t\t\t\treturn { operation: request.operation, data: comparePolicies(a, b) };\n\t\t\t}\n\t\t\tcase \"routing.policyPromote\": {\n\t\t\t\tif (!request.parameters?.authorized)\n\t\t\t\t\treturn { error: \"unauthorized\", message: \"policy promotion requires explicit authorization\" };\n\t\t\t\tconst res = promotePolicy(String(request.parameters.policyId ?? \"\"), \"rpc\", this.evidence(), {\n\t\t\t\t\tsafetyFloor: 0.5,\n\t\t\t\t\tcorrectnessFloor: 0.5,\n\t\t\t\t\tflakinessCeiling: 0.3,\n\t\t\t\t\trequiredScenarioPack: \"routing\",\n\t\t\t\t\toperatorAuthorized: true,\n\t\t\t\t});\n\t\t\t\treturn { operation: request.operation, data: res };\n\t\t\t}\n\t\t\tcase \"routing.policyRollback\": {\n\t\t\t\tif (!request.parameters?.authorized)\n\t\t\t\t\treturn { error: \"unauthorized\", message: \"policy rollback requires explicit authorization\" };\n\t\t\t\tconst res = rollbackPolicy(String(request.parameters.policyId ?? \"\"), \"rpc\");\n\t\t\t\treturn { operation: request.operation, data: res };\n\t\t\t}\n\t\t\tcase \"routing.driftStatus\":\n\t\t\t\treturn { operation: request.operation, data: { drift: checkDriftHealth(), dimensions: DRIFT_DIMS } };\n\t\t\tcase \"routing.driftInspect\": {\n\t\t\t\tconst dim = String(request.parameters?.dimension ?? \"quality\") as DriftDimension;\n\t\t\t\treturn { operation: request.operation, data: detectDrift(DRIFT_DIMS.includes(dim) ? dim : \"quality\", 0.1) };\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn { error: \"invalid_operation\", message: `Unknown routing RPC operation ${request.operation}` };\n\t\t}\n\t}\n}\n\nexport type RoutingRpcResponse = { operation: RoutingRpcOperation; data: unknown };\n\nfunction summarizeCandidate(c: OrchestrationCandidate): unknown {\n\treturn {\n\t\tproviderProfile: c.providerProfile,\n\t\tconfiguredModel: c.configuredModel,\n\t\texecutionTopology: c.executionTopology,\n\t\tretrievalPolicy: c.retrievalPolicy,\n\t\tbudgetClass: c.budgetClass,\n\t};\n}\n\nfunction notFound(id: string): RoutingRpcError {\n\treturn { error: \"not_found\", message: `Not found: ${id}` };\n}\n\nconst DRIFT_DIMS: DriftDimension[] = [\n\t\"quality\",\n\t\"cost\",\n\t\"latency\",\n\t\"failure_cluster\",\n\t\"retrieval\",\n\t\"task_distribution\",\n\t\"flakiness\",\n\t\"policy_selection\",\n];\n\nfunction routingStatusPayload(): unknown {\n\treturn {\n\t\tactivePolicy: activePolicyStatus(),\n\t\tdecisionsCount: listDecisions(10).length,\n\t\trecentDecisions: listDecisions(5).map((d) => ({\n\t\t\tdecisionId: d.decisionId,\n\t\t\tpolicyId: d.policyId,\n\t\t\tpolicyVersion: d.policyVersion,\n\t\t\tselectedCandidateId: d.selectedCandidateId,\n\t\t\tconfidence: d.confidence,\n\t\t})),\n\t\tshadowCount: listShadowDecisions(10).length,\n\t\tdriftHealth: checkDriftHealth(),\n\t};\n}\n"]}