{"version":3,"file":"lifecycle-executor.d.ts","sourceRoot":"","sources":["../../../src/core/orchestration/lifecycle-executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAwB,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAEpG,OAAO,KAAK,EACX,+BAA+B,EAC/B,kCAAkC,EAElC,iCAAiC,EAEjC,kBAAkB,EAClB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,qCAAqC;IACrD,4DAA4D;IAC5D,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,+DAA+D;IAC/D,KAAK,EAAE,kBAAkB,CAAC;IAC1B;;;;OAIG;IACH,KAAK,EAAE,SAAS,+BAA+B,EAAE,CAAC;CAClD;AAED,uEAAuE;AACvE,MAAM,WAAW,iCAAiC;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,YAAY,EAAE,OAAO,CAAC;IACtB,yDAAyD;IACzD,QAAQ,EAAE,OAAO,CAAC;IAClB,yDAAyD;IACzD,OAAO,CAAC,EAAE,kCAAkC,CAAC;CAC7C;AAED,4EAA4E;AAC5E,MAAM,WAAW,mCAAmC;IACnD,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,iCAAiC,EAAE,CAAC;IAC3C,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;GASG;AACH,wBAAsB,8BAA8B,CACnD,QAAQ,EAAE,mBAAmB,EAC7B,eAAe,EAAE,MAAM,EACvB,KAAK,EAAE,SAAS,+BAA+B,EAAE,GAC/C,OAAO,CAAC,+BAA+B,CAAC,CAW1C;AAaD,qBAAa,8BAA8B;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAuD;IAEzF,YAAY,OAAO,EAAE,qCAAqC,EAUzD;IAED,qDAAqD;IACrD,IAAI,WAAW,IAAI,SAAS,MAAM,EAAE,CAEnC;IAED;;;OAGG;IACG,WAAW,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,+BAA+B,CAAC,CAEnF;IAED;;;;;;;;;;;;;OAaG;IACG,cAAc,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,mCAAmC,CAAC,CAkC1F;IAED;;;;;;;;;;;;;;OAcG;IACG,WAAW,CAAC,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,iCAAiC,CAAC,CAiBrG;YAQa,wBAAwB;YAuBxB,SAAS;CAOvB;AAED,iFAAiF;AACjF,wBAAgB,oCAAoC,CACnD,OAAO,EAAE,qCAAqC,GAC5C,8BAA8B,CAEhC","sourcesContent":["/**\n * Parent orchestration lifecycle executor (2.15.0).\n *\n * The parent side of the child execution boundary. It owns the parent's\n * lifecycle step of driving a materialized orchestration toward execution\n * without ever launching anything itself and without re-implementing the\n * port's verification:\n *\n *   1. Load the parent mission from the durable mission store.\n *   2. Read the parent's durable execution contract\n *      (`MissionRequest.orchestrationExecution`) — the plan identity and the\n *      named child execution authority.\n *   3. Resolve the named authority against the registered ports'\n *      `authority` identities. Verified, never defaulted: an unknown\n *      authority is a hard error, and duplicate authority identities fail\n *      construction.\n *   4. Load the named plan and verify it belongs to this parent.\n *   5. Request execution of every materialized node through\n *      `port.executeChild` using the node's durable structured identity.\n *   6. Poll status/terminal outcome for a materialized node through the\n *      port's optional `childStatus` when the named authority provides it.\n *\n * The port remains the single verification and launch authority (it\n * re-verifies plan/node identity, child metadata, the parent's contract, and\n * terminal state, and owns the launch — Scheduler/Worker, local runtime, or\n * remote executor). This executor is read-only against both stores: it\n * never enqueues, assigns, starts, or launches, and it writes no plan or\n * mission state.\n */\n\nimport type { DurableMissionRecord, DurableMissionStore } from \"../mission-domain/durable-store.js\";\nimport type { MissionOrchestrationExecution } from \"../mission-domain/mission-request.js\";\nimport type {\n\tOrchestrationChildExecutionPort,\n\tOrchestrationChildExecutionReceipt,\n\tOrchestrationChildExecutionRequest,\n\tOrchestrationChildExecutionStatus,\n\tOrchestrationPlanDocument,\n\tOrchestrationStore,\n} from \"./types.js\";\n\nexport interface OrchestrationLifecycleExecutorOptions {\n\t/** Durable mission store for parent contract resolution. */\n\tmissions: DurableMissionStore;\n\t/** Orchestration plan store for materialized node identity. */\n\tstore: OrchestrationStore;\n\t/**\n\t * Registered child execution authorities. The parent's durable contract\n\t * names exactly one by `childExecutionAuthority`; a duplicate authority\n\t * identity is a construction error (verified, never defaulted).\n\t */\n\tports: readonly OrchestrationChildExecutionPort[];\n}\n\n/** Structured outcome for one plan node in a lifecycle launch pass. */\nexport interface OrchestrationLifecycleNodeOutcome {\n\tnodeId: string;\n\t/** True when the node carries a durable child identity (mission + session). */\n\tmaterialized: boolean;\n\t/** True when the port accepted the execution request. */\n\tlaunched: boolean;\n\t/** Authoritative port receipt for materialized nodes. */\n\treceipt?: OrchestrationChildExecutionReceipt;\n}\n\n/** Structured outcome of one lifecycle launch pass for a parent mission. */\nexport interface OrchestrationLifecycleLaunchOutcome {\n\tparentMissionId: string;\n\torchestrationId: string;\n\t/** Authority identity that handled the pass. */\n\tauthority: string;\n\tnodes: OrchestrationLifecycleNodeOutcome[];\n\tmaterializedCount: number;\n\tlaunchedCount: number;\n\tdeclinedCount: number;\n}\n\n/**\n * Resolve the child execution authority named by a parent mission's durable\n * contract against the registered ports.\n *\n * Throws (never defaults):\n *   - `PARENT_MISSION_NOT_FOUND` / `PARENT_MISSION_CORRUPT` — parent missing\n *   - `NO_ORCHESTRATION_EXECUTION_CONTRACT` — parent does not own an\n *     orchestration\n *   - `AUTHORITY_NOT_REGISTERED` — the named authority is not registered\n */\nexport async function resolveChildExecutionAuthority(\n\tmissions: DurableMissionStore,\n\tparentMissionId: string,\n\tports: readonly OrchestrationChildExecutionPort[],\n): Promise<OrchestrationChildExecutionPort> {\n\tconst parent = await loadParentMission(missions, parentMissionId);\n\tconst execution = parent.request.orchestrationExecution;\n\tif (!execution)\n\t\tthrow new Error(`NO_ORCHESTRATION_EXECUTION_CONTRACT: ${parentMissionId} names no orchestration execution`);\n\tconst port = ports.find((candidate) => candidate.authority === execution.childExecutionAuthority);\n\tif (!port)\n\t\tthrow new Error(\n\t\t\t`AUTHORITY_NOT_REGISTERED: no child execution authority registered for '${execution.childExecutionAuthority}'`,\n\t\t);\n\treturn port;\n}\n\nasync function loadParentMission(\n\tmissions: DurableMissionStore,\n\tparentMissionId: string,\n): Promise<DurableMissionRecord> {\n\tconst loaded = await missions.load(parentMissionId);\n\tif (loaded.status === \"missing\") throw new Error(`PARENT_MISSION_NOT_FOUND: ${parentMissionId}`);\n\tif (loaded.status === \"corrupt\")\n\t\tthrow new Error(`PARENT_MISSION_CORRUPT: ${parentMissionId} is corrupt: ${loaded.diagnostic}`);\n\treturn loaded.record;\n}\n\nexport class OrchestrationLifecycleExecutor {\n\tprivate readonly _missions: DurableMissionStore;\n\tprivate readonly _store: OrchestrationStore;\n\tprivate readonly _portsByAuthority: ReadonlyMap<string, OrchestrationChildExecutionPort>;\n\n\tconstructor(options: OrchestrationLifecycleExecutorOptions) {\n\t\tthis._missions = options.missions;\n\t\tthis._store = options.store;\n\t\tconst byAuthority = new Map<string, OrchestrationChildExecutionPort>();\n\t\tfor (const port of options.ports) {\n\t\t\tif (byAuthority.has(port.authority))\n\t\t\t\tthrow new Error(`DUPLICATE_AUTHORITY: child execution authority '${port.authority}' is registered twice`);\n\t\t\tbyAuthority.set(port.authority, port);\n\t\t}\n\t\tthis._portsByAuthority = byAuthority;\n\t}\n\n\t/** Registered authorities, in registration order. */\n\tget authorities(): readonly string[] {\n\t\treturn [...this._portsByAuthority.keys()];\n\t}\n\n\t/**\n\t * Resolve the child execution authority named by the parent's durable\n\t * contract. See `resolveChildExecutionAuthority` for the error contract.\n\t */\n\tasync resolvePort(parentMissionId: string): Promise<OrchestrationChildExecutionPort> {\n\t\treturn resolveChildExecutionAuthority(this._missions, parentMissionId, [...this._portsByAuthority.values()]);\n\t}\n\n\t/**\n\t * Drive one lifecycle launch pass for the parent mission's orchestration.\n\t *\n\t * Loads the parent's durable contract, resolves the named authority,\n\t * verifies the named plan belongs to this parent, and requests execution\n\t * of every materialized node through the port. Non-materialized nodes are\n\t * reported as such and never presented to the port. The port's receipt is\n\t * authoritative; the executor never launches and never writes state.\n\t *\n\t * Throws (never defaults): `PARENT_MISSION_NOT_FOUND`,\n\t * `PARENT_MISSION_CORRUPT`, `NO_ORCHESTRATION_EXECUTION_CONTRACT`,\n\t * `AUTHORITY_NOT_REGISTERED`, `ORCHESTRATION_NOT_FOUND`,\n\t * `ORCHESTRATION_PLAN_CORRUPT`, `ORCHESTRATION_PARENT_MISMATCH`.\n\t */\n\tasync launchChildren(parentMissionId: string): Promise<OrchestrationLifecycleLaunchOutcome> {\n\t\tconst { execution, port, document } = await this._resolveExecutionContext(parentMissionId);\n\n\t\tconst nodes: OrchestrationLifecycleNodeOutcome[] = [];\n\t\tlet launchedCount = 0;\n\t\tlet declinedCount = 0;\n\t\tfor (const node of document.plan.nodes) {\n\t\t\tconst childMissionId = node.childMissionId;\n\t\t\tconst childSessionId = node.childSessionId;\n\t\t\tif (!childMissionId || !childSessionId) {\n\t\t\t\tnodes.push({ nodeId: node.nodeId, materialized: false, launched: false });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst request: OrchestrationChildExecutionRequest = {\n\t\t\t\torchestrationId: execution.orchestrationId,\n\t\t\t\tnodeId: node.nodeId,\n\t\t\t\tchildMissionId,\n\t\t\t\tchildSessionId,\n\t\t\t\tworkspaceAccess: node.workspaceAccess,\n\t\t\t};\n\t\t\tconst receipt = await port.executeChild(request);\n\t\t\tif (receipt.accepted) launchedCount++;\n\t\t\telse declinedCount++;\n\t\t\tnodes.push({ nodeId: node.nodeId, materialized: true, launched: receipt.accepted, receipt });\n\t\t}\n\t\treturn {\n\t\t\tparentMissionId,\n\t\t\torchestrationId: execution.orchestrationId,\n\t\t\tauthority: port.authority,\n\t\t\tnodes,\n\t\t\tmaterializedCount: nodes.filter((outcome) => outcome.materialized).length,\n\t\t\tlaunchedCount,\n\t\t\tdeclinedCount,\n\t\t};\n\t}\n\n\t/**\n\t * Poll the status/terminal outcome of one materialized node through the\n\t * child execution authority named by the parent's durable contract.\n\t *\n\t * The request is built from the node's durable structured identity in the\n\t * plan — the caller never supplies child mission or session identity. The\n\t * port's polling is authoritative (it owns the read model); the executor\n\t * performs no launches and writes no state.\n\t *\n\t * Throws (never defaults): `PARENT_MISSION_NOT_FOUND`,\n\t * `PARENT_MISSION_CORRUPT`, `NO_ORCHESTRATION_EXECUTION_CONTRACT`,\n\t * `AUTHORITY_NOT_REGISTERED`, `ORCHESTRATION_NOT_FOUND`,\n\t * `ORCHESTRATION_PLAN_CORRUPT`, `ORCHESTRATION_PARENT_MISMATCH`,\n\t * `NODE_NOT_FOUND`, `CHILD_NOT_MATERIALIZED`, `PORT_LACKS_CHILD_STATUS`.\n\t */\n\tasync childStatus(parentMissionId: string, nodeId: string): Promise<OrchestrationChildExecutionStatus> {\n\t\tconst { execution, port, document } = await this._resolveExecutionContext(parentMissionId);\n\t\tconst node = document.plan.nodes.find((candidate) => candidate.nodeId === nodeId);\n\t\tif (!node) throw new Error(`NODE_NOT_FOUND: orchestration ${execution.orchestrationId} has no node ${nodeId}`);\n\t\tif (!node.childMissionId || !node.childSessionId)\n\t\t\tthrow new Error(`CHILD_NOT_MATERIALIZED: node ${nodeId} has no materialized child mission`);\n\t\tif (typeof port.childStatus !== \"function\")\n\t\t\tthrow new Error(\n\t\t\t\t`PORT_LACKS_CHILD_STATUS: child execution authority '${port.authority}' does not provide child status polling`,\n\t\t\t);\n\t\treturn port.childStatus({\n\t\t\torchestrationId: execution.orchestrationId,\n\t\t\tnodeId,\n\t\t\tchildMissionId: node.childMissionId,\n\t\t\tchildSessionId: node.childSessionId,\n\t\t\tworkspaceAccess: node.workspaceAccess,\n\t\t});\n\t}\n\n\t/**\n\t * Shared preamble for launch and status paths: load the parent mission,\n\t * verify its durable orchestration execution contract, resolve the named\n\t * authority (verified, never defaulted), and verify the named plan belongs\n\t * to this parent.\n\t */\n\tprivate async _resolveExecutionContext(parentMissionId: string): Promise<{\n\t\texecution: MissionOrchestrationExecution;\n\t\tport: OrchestrationChildExecutionPort;\n\t\tdocument: OrchestrationPlanDocument;\n\t}> {\n\t\tconst parent = await loadParentMission(this._missions, parentMissionId);\n\t\tconst execution = parent.request.orchestrationExecution;\n\t\tif (!execution)\n\t\t\tthrow new Error(`NO_ORCHESTRATION_EXECUTION_CONTRACT: ${parentMissionId} names no orchestration execution`);\n\t\tconst port = this._portsByAuthority.get(execution.childExecutionAuthority);\n\t\tif (!port)\n\t\t\tthrow new Error(\n\t\t\t\t`AUTHORITY_NOT_REGISTERED: no child execution authority registered for '${execution.childExecutionAuthority}'`,\n\t\t\t);\n\t\tconst document = await this._loadPlan(execution.orchestrationId);\n\t\tif (document.plan.parentMissionId !== parentMissionId)\n\t\t\tthrow new Error(\n\t\t\t\t`ORCHESTRATION_PARENT_MISMATCH: orchestration ${execution.orchestrationId} belongs to ` +\n\t\t\t\t\t`${document.plan.parentMissionId}, not ${parentMissionId}`,\n\t\t\t);\n\t\treturn { execution, port, document };\n\t}\n\n\tprivate async _loadPlan(orchestrationId: string): Promise<OrchestrationPlanDocument> {\n\t\tconst loaded = await this._store.load(orchestrationId);\n\t\tif (loaded.status === \"missing\") throw new Error(`ORCHESTRATION_NOT_FOUND: ${orchestrationId}`);\n\t\tif (loaded.status === \"corrupt\")\n\t\t\tthrow new Error(`ORCHESTRATION_PLAN_CORRUPT: ${orchestrationId} is corrupt: ${loaded.diagnostic}`);\n\t\treturn loaded.document;\n\t}\n}\n\n/** Build an `OrchestrationLifecycleExecutor` over the given stores and ports. */\nexport function createOrchestrationLifecycleExecutor(\n\toptions: OrchestrationLifecycleExecutorOptions,\n): OrchestrationLifecycleExecutor {\n\treturn new OrchestrationLifecycleExecutor(options);\n}\n"]}