{"version":3,"file":"assignment-store.d.ts","sourceRoot":"","sources":["../../../src/core/assignment/assignment-store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Assignment Foundation — domain-facing persistence port (2.11.0).\n *\n * Pure types + validation only. No filesystem, process, provider, scheduler,\n * or worker-daemon machinery. The concrete file store writes one small record\n * per assignment and keeps the \"current assignment\" flag on the record itself;\n * the current-assignment invariant is enforced by the per-mission cross-process\n * mutation lock, not by a separate mutable pointer file.\n *\n * Authority model:\n *   - An assignment records logical designation (mission → executor).\n *   - It is never execution ownership, never runtime incarnation, and never a\n *     MissionResult. Canonical mission completion remains authoritative.\n */\n\nimport { isSafeExecutorId } from \"../executor-registry/executor-registry-types.js\";\nimport { isSafeMissionId } from \"../mission-domain/durable-store.js\";\nimport { isMissionState } from \"../mission-domain/mission-state.js\";\nimport {\n\ttype AssignmentRecord,\n\ttype AssignmentState,\n\tisActiveAssignmentState,\n\tisAssignmentState,\n\tisSafeAssignmentId,\n} from \"./assignment-types.js\";\n\nexport const ASSIGNMENT_SCHEMA_VERSION = 1 as const;\n\n// =============================================================================\n// Store port result types\n// =============================================================================\n\nexport type AssignmentLoadResult =\n\t| { status: \"ok\"; record: AssignmentRecord }\n\t| { status: \"missing\" }\n\t| { status: \"corrupt\"; assignmentId: string; diagnostic: string };\n\n/** The assignment records for one mission, plus the current designation. */\nexport interface MissionAssignmentIndex {\n\tmissionId: string;\n\t/** All assignments for the mission, oldest first. */\n\trecords: AssignmentRecord[];\n\t/** The record with `current === true`, when one exists. */\n\tcurrent?: AssignmentRecord;\n}\n\n/** A store-level atomic mutation of a mission's assignment history. */\nexport type AssignmentMutation<T> =\n\t| { kind: \"write\"; records: AssignmentRecord[]; value: T }\n\t| { kind: \"noop\"; value: T };\n\nexport type AssignmentMutateResult<T> = { status: \"ok\"; value: T } | { status: \"corrupt\"; diagnostic: string };\n\n/** Bulk read result: all healthy records plus structurally-surfaced corrupt ids. */\nexport interface AssignmentListRecordsResult {\n\trecords: AssignmentRecord[];\n\tcorrupt: { assignmentId: string; diagnostic: string }[];\n}\n\n/**\n * Canonical assignment persistence port. Implementations must be crash-conscious\n * (atomic record replacement, schema validation on load, deterministic corrupt\n * handling) and must never fabricate a current assignment.\n */\nexport interface AssignmentStore {\n\treadonly storeId: string;\n\n\t/** Load a single assignment by its durable id. */\n\tload(assignmentId: string): Promise<AssignmentLoadResult>;\n\n\t/** All assignment ids (any mission), for scan-based listing. */\n\tlistAssignments(): Promise<string[]>;\n\n\t/** Bulk load every healthy record and surface corrupt ids structurally. */\n\tlistRecords(): Promise<AssignmentListRecordsResult>;\n\n\t/**\n\t * Atomically mutate a mission's assignment history across processes. The\n\t * callback receives the mission's current records (oldest first) and its\n\t * current assignment, and returns the replacement record set. The store\n\t * serializes mutations per mission and enforces the current invariant.\n\t */\n\tmutate<T>(\n\t\tmissionId: string,\n\t\tmutation: (index: MissionAssignmentIndex) => AssignmentMutation<T>,\n\t): Promise<AssignmentMutateResult<T>>;\n}\n\n// =============================================================================\n// Validation\n// =============================================================================\n\nexport type AssignmentParseResult = { ok: true; record: AssignmentRecord } | { ok: false; diagnostic: string };\n\nfunction invalid(why: string): AssignmentParseResult {\n\treturn { ok: false, diagnostic: why };\n}\n\nfunction isSafeInteger(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isSafeInteger(value);\n}\n\nfunction isStringArray(value: unknown): value is string[] {\n\treturn Array.isArray(value) && value.every((entry) => typeof entry === \"string\");\n}\n\nexport function validateMissionRequirements(value: unknown): string | undefined {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return \"requirements must be an object\";\n\tconst r = value as Record<string, unknown>;\n\tif (r.platform !== undefined) {\n\t\tif (typeof r.platform !== \"object\" || r.platform === null || Array.isArray(r.platform))\n\t\t\treturn \"requirements.platform must be an object\";\n\t\tconst p = r.platform as Record<string, unknown>;\n\t\tif (p.os !== undefined && typeof p.os !== \"string\") return \"requirements.platform.os must be a string\";\n\t\tif (p.arch !== undefined && typeof p.arch !== \"string\") return \"requirements.platform.arch must be a string\";\n\t}\n\tfor (const key of [\"execution\", \"providers\", \"models\", \"tools\", \"specialized\", \"extra\"] as const) {\n\t\tif (r[key] !== undefined && !isStringArray(r[key])) return `requirements.${key} must be a string array`;\n\t}\n\tif (r.labels !== undefined) {\n\t\tif (typeof r.labels !== \"object\" || r.labels === null || Array.isArray(r.labels))\n\t\t\treturn \"requirements.labels must be an object\";\n\t\tconst labels = r.labels as Record<string, unknown>;\n\t\tif (labels.required !== undefined && !isStringArray(labels.required))\n\t\t\treturn \"requirements.labels.required must be a string array\";\n\t\tif (labels.excluded !== undefined && !isStringArray(labels.excluded))\n\t\t\treturn \"requirements.labels.excluded must be a string array\";\n\t}\n\tif (r.executionMode !== undefined && r.executionMode !== \"local\" && r.executionMode !== \"remote\")\n\t\treturn \"requirements.executionMode must be local|remote\";\n\tif (r.preferences !== undefined) {\n\t\tif (typeof r.preferences !== \"object\" || r.preferences === null || Array.isArray(r.preferences))\n\t\t\treturn \"requirements.preferences must be an object\";\n\t\tconst prefs = r.preferences as Record<string, unknown>;\n\t\tif (prefs.executionMode !== undefined && prefs.executionMode !== \"local\" && prefs.executionMode !== \"remote\")\n\t\t\treturn \"requirements.preferences.executionMode must be local|remote\";\n\t\tif (prefs.executorId !== undefined && typeof prefs.executorId !== \"string\")\n\t\t\treturn \"requirements.preferences.executorId must be a string\";\n\t\tif (prefs.remoteTargetId !== undefined && typeof prefs.remoteTargetId !== \"string\")\n\t\t\treturn \"requirements.preferences.remoteTargetId must be a string\";\n\t}\n\treturn undefined;\n}\n\nfunction validateCompatibilityItem(value: unknown): string | undefined {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value))\n\t\treturn \"compatibility item must be an object\";\n\tconst item = value as Record<string, unknown>;\n\tif (typeof item.kind !== \"string\") return \"compatibility item.kind must be a string\";\n\tif (typeof item.requirement !== \"string\") return \"compatibility item.requirement must be a string\";\n\tif (item.observed !== undefined && typeof item.observed !== \"string\" && !Array.isArray(item.observed))\n\t\treturn \"compatibility item.observed must be a string or string array\";\n\treturn undefined;\n}\n\nfunction validateCompatibility(value: unknown): string | undefined {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return \"compatibility must be an object\";\n\tconst c = value as Record<string, unknown>;\n\tif (typeof c.compatible !== \"boolean\") return \"compatibility.compatible must be a boolean\";\n\tif (!Array.isArray(c.satisfied) || !Array.isArray(c.unsatisfied) || !Array.isArray(c.warnings))\n\t\treturn \"compatibility lists must be arrays\";\n\tfor (const list of [c.satisfied, c.unsatisfied]) {\n\t\tfor (const entry of list) {\n\t\t\tconst err = validateCompatibilityItem(entry);\n\t\t\tif (err) return err;\n\t\t}\n\t}\n\tif (!c.warnings.every((w) => typeof w === \"string\")) return \"compatibility.warnings must be strings\";\n\treturn undefined;\n}\n\nfunction validateRuntimeObservation(value: unknown): string | undefined {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value))\n\t\treturn \"runtime observation must be an object\";\n\tconst r = value as Record<string, unknown>;\n\tif (!isSafeInteger(r.runtimeEpoch)) return \"runtime observation.runtimeEpoch must be a safe integer\";\n\tif (!isSafeInteger(r.observedAtMs)) return \"runtime observation.observedAtMs must be a safe integer\";\n\tif (r.runtimeInstanceId !== undefined && typeof r.runtimeInstanceId !== \"string\")\n\t\treturn \"runtime observation.runtimeInstanceId must be a string\";\n\tconst statuses = new Set([\"REGISTERED\", \"ONLINE\", \"STALE\", \"OFFLINE\", \"RETIRED\", \"UNKNOWN\"]);\n\tif (typeof r.status !== \"string\" || !statuses.has(r.status)) return \"runtime observation.status is invalid\";\n\treturn undefined;\n}\n\nfunction validateOwnerIdentity(value: unknown): string | undefined {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value))\n\t\treturn \"executionOwnerIdentity must be an object\";\n\tconst o = value as Record<string, unknown>;\n\tif (typeof o.executorId !== \"string\" || o.executorId.length === 0)\n\t\treturn \"executionOwnerIdentity.executorId must be a string\";\n\tif (typeof o.runtimeInstanceId !== \"string\" || o.runtimeInstanceId.length === 0)\n\t\treturn \"executionOwnerIdentity.runtimeInstanceId must be a string\";\n\tif (!isSafeInteger(o.runtimeEpoch)) return \"executionOwnerIdentity.runtimeEpoch must be a safe integer\";\n\tif (typeof o.ownerId !== \"string\" || o.ownerId.length === 0)\n\t\treturn \"executionOwnerIdentity.ownerId must be a string\";\n\treturn undefined;\n}\n\n/**\n * Validate an untrusted persisted value into an AssignmentRecord. Corruption is\n * surfaced structurally (`ok: false`), never silently dropped or fabricated.\n */\nexport function parseAssignmentRecord(value: unknown): AssignmentParseResult {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return invalid(\"record must be an object\");\n\tconst doc = value as Record<string, unknown>;\n\n\tif (doc.schemaVersion !== ASSIGNMENT_SCHEMA_VERSION) {\n\t\treturn invalid(`unsupported schemaVersion: ${String(doc.schemaVersion)}`);\n\t}\n\tif (typeof doc.assignmentId !== \"string\" || !isSafeAssignmentId(doc.assignmentId))\n\t\treturn invalid(\"assignmentId is missing or unsafe\");\n\tconst assignmentId = doc.assignmentId;\n\n\tif (typeof doc.missionId !== \"string\" || !isSafeMissionId(doc.missionId))\n\t\treturn invalid(\"missionId is missing or unsafe\");\n\tif (typeof doc.executorId !== \"string\" || !isSafeExecutorId(doc.executorId))\n\t\treturn invalid(\"executorId is missing or unsafe\");\n\n\tif (!isSafeInteger(doc.createdAtMs) || !isSafeInteger(doc.updatedAtMs))\n\t\treturn invalid(\"timestamps must be safe integers\");\n\tif (!isSafeInteger(doc.revision) || (doc.revision as number) < 0)\n\t\treturn invalid(\"revision must be a non-negative integer\");\n\tif (typeof doc.current !== \"boolean\") return invalid(\"current must be a boolean\");\n\n\tif (!isAssignmentState(doc.state)) return invalid(`invalid assignment state: ${String(doc.state)}`);\n\tconst state = doc.state as AssignmentState;\n\n\t// Current/invariant consistency: only an active (non-terminal) assignment can\n\t// be current; a terminal assignment must never be current.\n\tif (doc.current === true && !isActiveAssignmentState(state)) {\n\t\treturn invalid(`a ${state} assignment cannot be current`);\n\t}\n\tif (doc.current === false && state === \"ASSIGNED\") {\n\t\treturn invalid(\"an ASSIGNED record must be current (ASSIGNED implies designation)\");\n\t}\n\n\tif (doc.assignedBy !== undefined && typeof doc.assignedBy !== \"string\")\n\t\treturn invalid(\"assignedBy must be a string when present\");\n\tif (doc.requirementsSnapshot !== undefined) {\n\t\tconst err = validateMissionRequirements(doc.requirementsSnapshot);\n\t\tif (err) return invalid(`requirementsSnapshot: ${err}`);\n\t}\n\tif (doc.compatibilitySnapshot !== undefined) {\n\t\tconst err = validateCompatibility(doc.compatibilitySnapshot);\n\t\tif (err) return invalid(`compatibilitySnapshot: ${err}`);\n\t}\n\tif (doc.executorRuntimeAtAssignment !== undefined) {\n\t\tconst err = validateRuntimeObservation(doc.executorRuntimeAtAssignment);\n\t\tif (err) return invalid(`executorRuntimeAtAssignment: ${err}`);\n\t}\n\tfor (const key of [\"acceptedAtMs\", \"executionStartedAtMs\", \"completedAtMs\", \"releasedAtMs\"] as const) {\n\t\tif (doc[key] !== undefined && !isSafeInteger(doc[key])) return invalid(`${key} must be a safe integer`);\n\t}\n\tfor (const key of [\"consumedByAttemptId\", \"consumedByExecutionId\"] as const) {\n\t\tif (doc[key] !== undefined && typeof doc[key] !== \"string\")\n\t\t\treturn invalid(`${key} must be a string when present`);\n\t}\n\tfor (const key of [\"supersededByAssignmentId\", \"supersedesAssignmentId\"] as const) {\n\t\tif (doc[key] !== undefined && (typeof doc[key] !== \"string\" || !isSafeAssignmentId(doc[key])))\n\t\t\treturn invalid(`${key} must be a safe assignment id when present`);\n\t}\n\tif (doc.executionOwnerIdentity !== undefined) {\n\t\tconst err = validateOwnerIdentity(doc.executionOwnerIdentity);\n\t\tif (err) return invalid(`executionOwnerIdentity: ${err}`);\n\t}\n\tif (doc.executionMode !== undefined && doc.executionMode !== \"local\" && doc.executionMode !== \"remote\")\n\t\treturn invalid(\"executionMode must be local|remote when present\");\n\tif (doc.remoteTargetId !== undefined && typeof doc.remoteTargetId !== \"string\")\n\t\treturn invalid(\"remoteTargetId must be a string when present\");\n\tif (doc.terminalMissionState !== undefined && !isMissionState(doc.terminalMissionState))\n\t\treturn invalid(\"terminalMissionState is invalid\");\n\tif (doc.reason !== undefined && typeof doc.reason !== \"string\")\n\t\treturn invalid(\"reason must be a string when present\");\n\n\treturn {\n\t\tok: true,\n\t\trecord: {\n\t\t\tschemaVersion: ASSIGNMENT_SCHEMA_VERSION,\n\t\t\tassignmentId,\n\t\t\tmissionId: doc.missionId as string,\n\t\t\texecutorId: doc.executorId as string,\n\t\t\tcreatedAtMs: doc.createdAtMs as number,\n\t\t\tupdatedAtMs: doc.updatedAtMs as number,\n\t\t\tstate,\n\t\t\tcurrent: doc.current as boolean,\n\t\t\tassignedBy: doc.assignedBy as string | undefined,\n\t\t\trequirementsSnapshot: doc.requirementsSnapshot as AssignmentRecord[\"requirementsSnapshot\"],\n\t\t\tcompatibilitySnapshot: doc.compatibilitySnapshot as AssignmentRecord[\"compatibilitySnapshot\"],\n\t\t\texecutionMode: doc.executionMode as AssignmentRecord[\"executionMode\"],\n\t\t\tremoteTargetId: doc.remoteTargetId as AssignmentRecord[\"remoteTargetId\"],\n\t\t\texecutorRuntimeAtAssignment:\n\t\t\t\tdoc.executorRuntimeAtAssignment as AssignmentRecord[\"executorRuntimeAtAssignment\"],\n\t\t\tacceptedAtMs: doc.acceptedAtMs as number | undefined,\n\t\t\texecutionStartedAtMs: doc.executionStartedAtMs as number | undefined,\n\t\t\tcompletedAtMs: doc.completedAtMs as number | undefined,\n\t\t\treleasedAtMs: doc.releasedAtMs as number | undefined,\n\t\t\tconsumedByAttemptId: doc.consumedByAttemptId as string | undefined,\n\t\t\tconsumedByExecutionId: doc.consumedByExecutionId as string | undefined,\n\t\t\tsupersededByAssignmentId: doc.supersededByAssignmentId as string | undefined,\n\t\t\tsupersedesAssignmentId: doc.supersedesAssignmentId as string | undefined,\n\t\t\texecutionOwnerIdentity: doc.executionOwnerIdentity as AssignmentRecord[\"executionOwnerIdentity\"],\n\t\t\tterminalMissionState: doc.terminalMissionState as AssignmentRecord[\"terminalMissionState\"],\n\t\t\treason: doc.reason as string | undefined,\n\t\t\trevision: doc.revision as number,\n\t\t},\n\t};\n}\n\n// =============================================================================\n// Record construction helper\n// =============================================================================\n\nexport interface CreateAssignmentRecordInput {\n\tassignmentId: string;\n\tmissionId: string;\n\texecutorId: string;\n\tnow?: number;\n\tassignedBy?: string;\n\trequirementsSnapshot?: AssignmentRecord[\"requirementsSnapshot\"];\n\tcompatibilitySnapshot?: AssignmentRecord[\"compatibilitySnapshot\"];\n\texecutionMode?: AssignmentRecord[\"executionMode\"];\n\tremoteTargetId?: AssignmentRecord[\"remoteTargetId\"];\n\texecutorRuntimeAtAssignment?: AssignmentRecord[\"executorRuntimeAtAssignment\"];\n}\n\n/** Build an initial ASSIGNED + current record. */\nexport function createAssignmentRecord(input: CreateAssignmentRecordInput): AssignmentRecord {\n\tif (!isSafeAssignmentId(input.assignmentId)) throw new Error(`Unsafe assignment id: ${input.assignmentId}`);\n\tif (!isSafeMissionId(input.missionId)) throw new Error(`Unsafe mission id: ${input.missionId}`);\n\tif (!isSafeExecutorId(input.executorId)) throw new Error(`Unsafe executor id: ${input.executorId}`);\n\tconst now = input.now ?? Date.now();\n\treturn {\n\t\tschemaVersion: ASSIGNMENT_SCHEMA_VERSION,\n\t\tassignmentId: input.assignmentId,\n\t\tmissionId: input.missionId,\n\t\texecutorId: input.executorId,\n\t\tcreatedAtMs: now,\n\t\tupdatedAtMs: now,\n\t\tstate: \"ASSIGNED\",\n\t\tcurrent: true,\n\t\tassignedBy: input.assignedBy,\n\t\trequirementsSnapshot: input.requirementsSnapshot,\n\t\tcompatibilitySnapshot: input.compatibilitySnapshot,\n\t\texecutionMode: input.executionMode,\n\t\tremoteTargetId: input.remoteTargetId,\n\t\texecutorRuntimeAtAssignment: input.executorRuntimeAtAssignment,\n\t\trevision: 1,\n\t};\n}\n\n/** True when a record represents a canonical terminal assignment outcome. */\nexport function isTerminalAssignmentRecord(record: AssignmentRecord): boolean {\n\treturn !isActiveAssignmentState(record.state);\n}\n"]}