@open-mercato/core 0.9.1-develop.7519.1.38f51f8dbb → 0.9.1-develop.7532.1.8eac7e198f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/auth/api/logout.js +6 -1
  3. package/dist/modules/auth/api/logout.js.map +2 -2
  4. package/dist/modules/auth/api/session/refresh.js +6 -1
  5. package/dist/modules/auth/api/session/refresh.js.map +2 -2
  6. package/dist/modules/catalog/ai-tools/mutation-pack.js +10 -5
  7. package/dist/modules/catalog/ai-tools/mutation-pack.js.map +2 -2
  8. package/dist/modules/catalog/ai-tools/types.js.map +2 -2
  9. package/dist/modules/customer_accounts/api/login.js +14 -7
  10. package/dist/modules/customer_accounts/api/login.js.map +2 -2
  11. package/dist/modules/customer_accounts/services/customerUserService.js +10 -10
  12. package/dist/modules/customer_accounts/services/customerUserService.js.map +2 -2
  13. package/dist/modules/forms/api/distributions/[distributionId]/invitations/[invitationId]/route.js +1 -1
  14. package/dist/modules/forms/api/distributions/[distributionId]/invitations/[invitationId]/route.js.map +1 -1
  15. package/dist/modules/forms/api/form-submissions/[id]/submit/route.js +12 -2
  16. package/dist/modules/forms/api/form-submissions/[id]/submit/route.js.map +2 -2
  17. package/dist/modules/forms/api/form-submissions/route.js +16 -1
  18. package/dist/modules/forms/api/form-submissions/route.js.map +2 -2
  19. package/dist/modules/forms/api/public/submissions/[id]/submit/route.js +6 -1
  20. package/dist/modules/forms/api/public/submissions/[id]/submit/route.js.map +2 -2
  21. package/dist/modules/forms/api/runtime-helpers.js +16 -0
  22. package/dist/modules/forms/api/runtime-helpers.js.map +2 -2
  23. package/dist/modules/forms/data/validators.js.map +2 -2
  24. package/dist/modules/forms/lib/portal-subject-policy.js +17 -0
  25. package/dist/modules/forms/lib/portal-subject-policy.js.map +7 -0
  26. package/dist/modules/forms/lib/runtime-principal.js +27 -10
  27. package/dist/modules/forms/lib/runtime-principal.js.map +2 -2
  28. package/dist/modules/forms/services/distribution-service.js +35 -13
  29. package/dist/modules/forms/services/distribution-service.js.map +2 -2
  30. package/dist/modules/forms/services/submission-service.js +4 -0
  31. package/dist/modules/forms/services/submission-service.js.map +2 -2
  32. package/dist/modules/staff/commands/leave-requests.js +54 -24
  33. package/dist/modules/staff/commands/leave-requests.js.map +2 -2
  34. package/dist/modules/warranty_claims/api/portal/attachments/route.js +19 -7
  35. package/dist/modules/warranty_claims/api/portal/attachments/route.js.map +2 -2
  36. package/dist/modules/warranty_claims/commands/claims.js +1 -1
  37. package/dist/modules/warranty_claims/commands/claims.js.map +2 -2
  38. package/dist/modules/warranty_claims/subscribers/return-shipment-tracking.js +6 -6
  39. package/dist/modules/warranty_claims/subscribers/return-shipment-tracking.js.map +2 -2
  40. package/dist/modules/wms/commands/inventory-actions.js +19 -3
  41. package/dist/modules/wms/commands/inventory-actions.js.map +2 -2
  42. package/dist/modules/workflows/lib/async-activity-wait.js +43 -0
  43. package/dist/modules/workflows/lib/async-activity-wait.js.map +7 -0
  44. package/dist/modules/workflows/lib/parallel-handler.js +20 -14
  45. package/dist/modules/workflows/lib/parallel-handler.js.map +2 -2
  46. package/dist/modules/workflows/lib/workflow-executor.js +21 -23
  47. package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
  48. package/package.json +7 -7
  49. package/src/modules/auth/api/logout.ts +6 -1
  50. package/src/modules/auth/api/session/refresh.ts +6 -1
  51. package/src/modules/catalog/ai-tools/mutation-pack.ts +14 -5
  52. package/src/modules/catalog/ai-tools/types.ts +1 -0
  53. package/src/modules/customer_accounts/api/login.ts +15 -7
  54. package/src/modules/customer_accounts/services/customerUserService.ts +34 -10
  55. package/src/modules/forms/api/distributions/[distributionId]/invitations/[invitationId]/route.ts +1 -1
  56. package/src/modules/forms/api/form-submissions/[id]/submit/route.ts +16 -3
  57. package/src/modules/forms/api/form-submissions/route.ts +21 -2
  58. package/src/modules/forms/api/public/submissions/[id]/submit/route.ts +7 -0
  59. package/src/modules/forms/api/runtime-helpers.ts +16 -0
  60. package/src/modules/forms/data/validators.ts +2 -1
  61. package/src/modules/forms/i18n/de.json +1 -0
  62. package/src/modules/forms/i18n/en.json +1 -0
  63. package/src/modules/forms/i18n/es.json +1 -0
  64. package/src/modules/forms/i18n/ko.json +1 -0
  65. package/src/modules/forms/i18n/pl.json +1 -0
  66. package/src/modules/forms/lib/portal-subject-policy.ts +42 -0
  67. package/src/modules/forms/lib/runtime-principal.ts +35 -11
  68. package/src/modules/forms/services/distribution-service.ts +35 -13
  69. package/src/modules/forms/services/submission-service.ts +12 -0
  70. package/src/modules/staff/commands/leave-requests.ts +54 -23
  71. package/src/modules/staff/i18n/de.json +2 -0
  72. package/src/modules/staff/i18n/en.json +2 -0
  73. package/src/modules/staff/i18n/es.json +2 -0
  74. package/src/modules/staff/i18n/ko.json +2 -0
  75. package/src/modules/staff/i18n/pl.json +2 -0
  76. package/src/modules/warranty_claims/api/portal/attachments/route.ts +20 -8
  77. package/src/modules/warranty_claims/commands/claims.ts +1 -1
  78. package/src/modules/warranty_claims/subscribers/return-shipment-tracking.ts +5 -5
  79. package/src/modules/wms/commands/inventory-actions.ts +30 -10
  80. package/src/modules/workflows/lib/async-activity-wait.ts +71 -0
  81. package/src/modules/workflows/lib/parallel-handler.ts +24 -15
  82. package/src/modules/workflows/lib/workflow-executor.ts +24 -27
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/workflows/lib/workflow-executor.ts"],
4
- "sourcesContent": ["/**\n * Workflows Module - Workflow Executor Service\n *\n * Main orchestrator for workflow execution. Handles workflow lifecycle:\n * - Starting workflow instances from definitions\n * - Executing workflow steps and transitions\n * - Completing workflows with final status\n * - Triggering compensation on failure\n *\n * Functional API (no classes) following Open Mercato conventions.\n */\n\nimport { EntityManager, LockMode } from '@mikro-orm/core'\nimport type { EntityManager as PostgreSqlEntityManager } from '@mikro-orm/postgresql'\nimport type { AwilixContainer } from 'awilix'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport {\n WorkflowDefinition,\n WorkflowInstance,\n WorkflowEvent,\n type WorkflowInstanceStatus,\n type WorkflowInstanceErrorHandlerMetadata,\n} from '../data/entities'\nimport { compensateWorkflow } from './compensation-handler'\nimport { WORKFLOW_ENGINE_VERSION, isEngineVersionSupported } from './engine-version'\nimport {\n WORKFLOW_ERROR_CONTEXT_KEY,\n buildErrorContextEntry,\n} from './error-routing'\nimport { excludeNonNormalTransitions } from './route-kinds'\nimport {\n WORKFLOW_AGENT_OUTCOME_CONTEXT_KEY,\n readAgentOutcomeMarker,\n resolveAgentOutcomeHandling,\n type OutcomeRoutingDefinitionLike,\n type WorkflowAgentOutcomeContextEntry,\n} from './outcome-routing'\nimport { scheduleWorkflowErrorHandler } from './error-handler'\nimport { resolveRunOutcome } from './run-outcome'\nimport { collectRunOutcomeEvidence } from './run-outcome-evidence'\nimport { findWorkflowDefinition, findDefinitionForInstance } from './find-definition'\nimport { resolveWorkflowDefinitionExecutionUserId } from './definition-grant'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { emitWorkflowsEvent } from '../events'\nimport { DRY_RUN_EVENT_TYPES } from './dry-run'\nimport {\n STEP_THROUGH_EVENT_TYPE,\n consumeStepThroughRelease,\n isStepThroughArmed,\n shouldPauseForStepThrough,\n} from './step-through'\nimport type {\n WorkflowActivityJob,\n WorkflowActivityJobResumeSubWorkflowParent,\n} from './activity-queue-types'\n\nconst logger = createLogger('workflows')\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface StartWorkflowOptions {\n workflowId: string\n version?: number // Default to latest enabled version\n initialContext?: Record<string, any>\n correlationKey?: string\n metadata?: {\n entityType?: string\n entityId?: string\n initiatedBy?: string\n labels?: Record<string, string>\n // Set by the workflow-level error handler when it starts a handler run, so\n // the depth guard travels with the child instance (spec 5.9).\n errorHandler?: WorkflowInstanceErrorHandlerMetadata | null\n }\n /**\n * Run this instance as a side-effect-free simulation (spec section 8.2).\n *\n * It is durable state on the row rather than a per-call argument because a\n * run outlives the call that started it: it parks on a signal, resumes from a\n * worker, is advanced by a task completion. Anything that only lived on this\n * options object would stop protecting the run the moment it suspended.\n */\n isDryRun?: boolean\n tenantId: string\n organizationId: string\n}\n\nexport interface ExecutionContext {\n userId?: string\n /**\n * @deprecated Never read, and never was. Dry-run state lives on\n * `WorkflowInstance.isDryRun` (spec section 8.2) because a per-execution flag\n * cannot survive the instance parking on a signal and resuming inside a\n * worker \u2014 which is exactly when a leak would happen. Kept as an inert field\n * for one minor per `BACKWARD_COMPATIBILITY.md`; pass `isDryRun` to\n * `startWorkflow` instead.\n */\n dryRun?: boolean\n timeout?: number\n}\n\nexport interface ExecutionResult {\n status: WorkflowInstanceStatus\n currentStep: string\n context: Record<string, any>\n events: WorkflowEventSummary[]\n errors?: string[]\n executionTime: number\n}\n\nexport interface WorkflowEventSummary {\n eventType: string\n occurredAt: Date\n data?: any\n}\n\nfunction normalizeWorkflowUserId(value: unknown): string | null {\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n if (!trimmed || trimmed.startsWith('trigger:')) return null\n return trimmed\n}\n\nfunction resolveWorkflowExecutionUserId(\n context: ExecutionContext | undefined,\n instance: WorkflowInstance,\n): string | undefined {\n return (\n normalizeWorkflowUserId(context?.userId) ??\n normalizeWorkflowUserId(instance.metadata?.initiatedBy) ??\n undefined\n )\n}\n\n/**\n * The identity this run advances under.\n *\n * A definition declaring `grantedFeatures` ALWAYS acts as its own least-\n * privilege principal, so a run started by an admin cannot silently gain the\n * admin's powers and an event-triggered run (which has no actor at all) gets a\n * real one. Everything else keeps the historic borrow-the-starting-user\n * behaviour, byte-for-byte.\n */\nasync function resolveRunActorUserId(\n em: EntityManager,\n definition: WorkflowDefinition,\n context: ExecutionContext | undefined,\n instance: WorkflowInstance,\n): Promise<string | undefined> {\n const fallback = resolveWorkflowExecutionUserId(context, instance)\n const actor = await resolveWorkflowDefinitionExecutionUserId(\n em as unknown as PostgreSqlEntityManager,\n definition,\n fallback,\n )\n return actor ?? undefined\n}\n\nexport class WorkflowExecutionError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: any\n ) {\n super(message)\n this.name = 'WorkflowExecutionError'\n }\n}\n\n// ============================================================================\n// Main Orchestration Functions\n// ============================================================================\n\n/**\n * Start a new workflow instance from a definition\n *\n * @param em - Entity manager for database operations\n * @param options - Workflow start options\n * @returns Created workflow instance\n * @throws WorkflowExecutionError if definition not found or validation fails\n */\nexport async function startWorkflow(\n em: EntityManager,\n options: StartWorkflowOptions\n): Promise<WorkflowInstance> {\n const {\n workflowId,\n version,\n initialContext = {},\n correlationKey,\n metadata,\n isDryRun = false,\n tenantId,\n organizationId,\n } = options\n\n // Find workflow definition\n const definition = await findWorkflowDefinition(em, {\n workflowId,\n version,\n tenantId,\n organizationId,\n })\n\n if (!definition) {\n throw new WorkflowExecutionError(\n `Workflow definition not found: ${workflowId}${version ? ` v${version}` : ''}`,\n 'DEFINITION_NOT_FOUND',\n { workflowId, version }\n )\n }\n\n if (!definition.enabled) {\n throw new WorkflowExecutionError(\n `Workflow definition is disabled: ${workflowId}`,\n 'DEFINITION_DISABLED',\n { workflowId, version: definition.version }\n )\n }\n\n // Forward-compatibility guard: a definition authored against a newer engine\n // is refused outright rather than executed with unknown step types treated\n // as no-ops (spec section 5.8).\n const minEngineVersion = definition.metadata?.minEngineVersion\n if (!isEngineVersionSupported(minEngineVersion)) {\n throw new WorkflowExecutionError(\n `Workflow definition requires engine version ${minEngineVersion}, this engine is version ${WORKFLOW_ENGINE_VERSION}`,\n 'ENGINE_VERSION_TOO_OLD',\n { workflowId, version: definition.version, minEngineVersion, engineVersion: WORKFLOW_ENGINE_VERSION }\n )\n }\n\n // Validate definition has required steps\n const { steps, transitions } = definition.definition\n if (!steps || steps.length < 2) {\n throw new WorkflowExecutionError(\n 'Workflow definition must have at least START and END steps',\n 'INVALID_DEFINITION',\n { workflowId, stepsCount: steps?.length || 0 }\n )\n }\n\n if (!transitions || transitions.length < 1) {\n throw new WorkflowExecutionError(\n 'Workflow definition must have at least one transition',\n 'INVALID_DEFINITION',\n { workflowId, transitionsCount: transitions?.length || 0 }\n )\n }\n\n // Find START step\n const startStep = steps.find((s: any) => s.stepType === 'START')\n if (!startStep) {\n throw new WorkflowExecutionError(\n 'Workflow definition must have a START step',\n 'INVALID_DEFINITION',\n { workflowId }\n )\n }\n\n // Validate START step pre-conditions if defined\n if (startStep.preConditions && startStep.preConditions.length > 0) {\n const { validateWorkflowStart } = await import('./start-validator')\n\n const validationResult = await validateWorkflowStart(em, {\n workflowId,\n version: definition.version,\n context: initialContext,\n tenantId,\n organizationId,\n })\n\n if (!validationResult.canStart) {\n throw new WorkflowExecutionError(\n `Workflow start pre-conditions failed: ${validationResult.errors.map(e => e.message).join('; ')}`,\n 'START_PRE_CONDITIONS_FAILED',\n {\n workflowId,\n errors: validationResult.errors,\n validatedRules: validationResult.validatedRules,\n }\n )\n }\n }\n\n // Create workflow instance\n const now = new Date()\n const instance = em.create(WorkflowInstance, {\n definitionId: definition.id,\n workflowId: definition.workflowId,\n version: definition.version,\n status: 'RUNNING',\n currentStepId: startStep.stepId,\n context: initialContext,\n correlationKey,\n metadata,\n startedAt: now,\n retryCount: 0,\n isDryRun,\n tenantId,\n organizationId,\n createdAt: now,\n updatedAt: now,\n })\n\n await em.persist(instance).flush()\n\n // Log WORKFLOW_STARTED event\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'WORKFLOW_STARTED',\n eventData: {\n workflowId: instance.workflowId,\n version: instance.version,\n startStepId: startStep.stepId,\n initialContext,\n metadata,\n },\n userId: metadata?.initiatedBy,\n tenantId,\n organizationId,\n })\n\n if (isDryRun) {\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: DRY_RUN_EVENT_TYPES.started,\n eventData: { workflowId: instance.workflowId, version: instance.version },\n userId: metadata?.initiatedBy,\n tenantId,\n organizationId,\n })\n }\n\n await emitInstanceLifecycleEvent(instance, 'workflows.instance.created')\n await emitInstanceLifecycleEvent(instance, 'workflows.instance.started')\n\n return instance\n}\n\n/**\n * Execute a workflow instance\n *\n * Main execution loop that processes steps and transitions until:\n * - Workflow completes (reaches END step)\n * - Workflow waits (USER_TASK, SIGNAL, TIMER)\n * - Workflow fails (error occurs)\n * - Timeout is reached\n *\n * @param em - Entity manager\n * @param container - DI container (for activity execution and other services)\n * @param instanceId - Workflow instance ID\n * @param context - Execution context (userId, dryRun, timeout)\n * @returns Execution result with status and events\n */\nexport async function executeWorkflow(\n em: EntityManager,\n container: AwilixContainer,\n instanceId: string,\n context?: ExecutionContext\n): Promise<ExecutionResult> {\n const startTime = Date.now()\n const transactionalEm = em as EntityManager & {\n transactional?: <TResult>(\n callback: (trx: EntityManager) => Promise<TResult>,\n ) => Promise<TResult>\n }\n\n const runExecution = async (trx: EntityManager): Promise<ExecutionResult> => {\n const events: WorkflowEventSummary[] = []\n const errors: string[] = []\n\n try {\n const instance = await getWorkflowInstanceForExecution(trx, instanceId)\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n if (instance.status === 'COMPLETED') {\n return {\n status: 'COMPLETED',\n currentStep: instance.currentStepId,\n context: instance.context,\n events: [],\n executionTime: 0,\n }\n }\n\n if (instance.status === 'CANCELLED') {\n throw new WorkflowExecutionError(\n 'Cannot execute cancelled workflow',\n 'WORKFLOW_CANCELLED',\n { instanceId, status: instance.status }\n )\n }\n\n const definition = await findDefinitionForInstance(trx, instance)\n\n if (!definition) {\n throw new WorkflowExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n const maxIterations = 100\n let iterations = 0\n const executionUserId = await resolveRunActorUserId(trx, definition, context, instance)\n\n while (iterations < maxIterations) {\n iterations++\n\n const currentInstance = await getWorkflowInstanceForExecution(trx, instanceId, { refresh: iterations > 1 })\n if (!currentInstance) {\n throw new WorkflowExecutionError(\n 'Instance not found during execution',\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n // Parallel execution: while the instance is FORKED, drive the branches.\n if (currentInstance.status === 'FORKED') {\n const { advanceBranches } = await import('./parallel-handler')\n const branchResult = await advanceBranches(trx, container, currentInstance, definition, {\n userId: executionUserId,\n })\n\n if (branchResult.outcome === 'joined') {\n // Instance resumed at the post-join step; continue single-token.\n continue\n }\n\n if (branchResult.outcome === 'failed') {\n errors.push(branchResult.error || 'Parallel branch failed')\n await completeWorkflow(trx, container, instanceId, 'FAILED', {\n error: branchResult.error || 'Parallel branch failed',\n })\n return {\n status: 'FAILED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n }\n\n // 'waiting' \u2014 all branches paused for external resume (task/signal/timer/async).\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n // Defense in depth: a prior step parked the instance (e.g. an\n // INVOKE_AGENT AUTOMATED step set PAUSED, or a transition set\n // WAITING_FOR_ACTIVITIES). Every resume path (sendSignal,\n // resumeWorkflowAfterActivities) flips status back to RUNNING before\n // re-entering, so a PAUSED/WAITING_FOR_ACTIVITIES status here means an\n // external completion is still pending \u2014 stop advancing.\n if (currentInstance.status === 'PAUSED' || currentInstance.status === 'WAITING_FOR_ACTIVITIES') {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const currentStep = definition.definition.steps.find(\n (s: any) => s.stepId === currentInstance.currentStepId\n )\n\n // Step-through (spec section 8.2). An instance-level PAUSED between\n // steps \u2014 no new instance status and no new step status, so the state\n // machines are untouched. The marker is a RELEASE TOKEN for exactly one\n // step id, so replaying this loop after a crash cannot run a step the\n // author never released, and a double Continue cannot run two.\n if (\n shouldPauseForStepThrough(\n currentInstance,\n currentInstance.currentStepId,\n currentStep?.stepType\n )\n ) {\n await pauseForStepThrough(trx, currentInstance)\n events.push({\n eventType: STEP_THROUGH_EVENT_TYPE,\n occurredAt: new Date(),\n data: { stepId: currentInstance.currentStepId },\n })\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n if (isStepThroughArmed(currentInstance)) {\n // The released step is about to run: burn the token now so the cursor\n // landing on the NEXT step pauses, whatever route it takes.\n currentInstance.metadata = {\n ...(currentInstance.metadata || {}),\n stepThrough: consumeStepThroughRelease(),\n }\n currentInstance.updatedAt = new Date()\n await trx.flush()\n }\n\n if (currentStep?.stepType === 'END') {\n await completeWorkflow(trx, container, instanceId, 'COMPLETED')\n events.push({\n eventType: 'WORKFLOW_COMPLETED',\n occurredAt: new Date(),\n })\n\n return {\n status: 'COMPLETED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n if (\n currentStep?.stepType === 'USER_TASK' ||\n currentStep?.stepType === 'WAIT_FOR_SIGNAL' ||\n currentStep?.stepType === 'WAIT_FOR_TIMER'\n ) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n // Outcome routing (spec 7.2). An agent step that resolved a disposition\n // leaves an engine-owned marker; a wired outcome route is followed\n // declaratively instead of via a condition matching a context string.\n // `default` \u2014 the marker's absence, or a step that wired no outcome at\n // all \u2014 falls straight through to the normal routing below, which is the\n // whole of the backward-compatibility guarantee.\n const outcomeMarker = readAgentOutcomeMarker(\n currentInstance.context,\n currentInstance.currentStepId ?? '',\n )\n if (outcomeMarker) {\n const dispatched = await dispatchAgentOutcome(\n trx,\n container,\n currentInstance,\n definition.definition,\n outcomeMarker,\n { workflowContext: currentInstance.context, userId: executionUserId },\n )\n if (dispatched.kind === 'routed') {\n events.push({\n eventType: 'OUTCOME_ROUTED',\n occurredAt: new Date(),\n data: {\n stepId: outcomeMarker.stepId,\n outcome: outcomeMarker.outcome,\n toStepId: dispatched.toStepId,\n transitionId: dispatched.transitionId,\n },\n })\n continue\n }\n if (dispatched.kind === 'failed') {\n errors.push(dispatched.error)\n events.push({\n eventType: 'OUTCOME_UNHANDLED',\n occurredAt: new Date(),\n data: { stepId: outcomeMarker.stepId, outcome: outcomeMarker.outcome },\n })\n await completeWorkflow(trx, container, instanceId, 'FAILED', { error: dispatched.error })\n return {\n status: 'FAILED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n }\n if (dispatched.kind === 'parked') {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n }\n\n const transitions = excludeNonNormalTransitions(definition.definition.transitions).filter(\n (t: any) =>\n t.fromStepId === currentInstance.currentStepId &&\n t.trigger === 'auto'\n )\n\n if (transitions.length === 0) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const transitionHandler = await import('./transition-handler')\n const evalContext: any = {\n workflowContext: currentInstance.context,\n userId: executionUserId,\n }\n\n const validTransitions = await transitionHandler.findValidTransitions(\n trx,\n currentInstance,\n currentInstance.currentStepId!,\n evalContext\n )\n\n const validAutoTransitions = validTransitions.filter(\n (vt) => vt.isValid && vt.transition?.trigger === 'auto'\n )\n\n if (validAutoTransitions.length === 0) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const selectedTransition = validAutoTransitions[0].transition\n\n try {\n const transitionResult = await transitionHandler.executeTransition(\n trx,\n container,\n currentInstance,\n selectedTransition.fromStepId,\n selectedTransition.toStepId,\n { ...evalContext, transitionId: selectedTransition.transitionId },\n )\n\n if (!transitionResult.success) {\n const rejectionMessage = transitionResult.error || 'Transition failed'\n\n // Error routing (spec 5.9): a wired error route is followed instead\n // of failing the instance; a failure-queue directive parks it. Both\n // are absent unless the definition opts in, so the legacy failure\n // path below is byte-identical for every existing definition.\n if (transitionResult.errorRoute && transitionResult.failedStepId) {\n const routed = await followErrorRoute(\n trx,\n container,\n currentInstance,\n transitionResult.failedStepId,\n transitionResult.errorRoute,\n rejectionMessage,\n evalContext\n )\n if (routed) {\n events.push({\n eventType: 'ERROR_ROUTED',\n occurredAt: new Date(),\n data: {\n failedStepId: transitionResult.failedStepId,\n toStepId: transitionResult.errorRoute.toStepId,\n transitionId: transitionResult.errorRoute.transitionId,\n },\n })\n continue\n }\n errors.push(`Error route from ${transitionResult.failedStepId} could not be followed`)\n }\n\n if (transitionResult.errorHandlerStepId && transitionResult.failedStepId) {\n const entered = await enterErrorHandlerStep(\n trx,\n container,\n currentInstance,\n transitionResult.failedStepId,\n transitionResult.errorHandlerStepId,\n rejectionMessage,\n executionUserId\n )\n if (entered) {\n events.push({\n eventType: 'ERROR_HANDLER_STARTED',\n occurredAt: new Date(),\n data: {\n failedStepId: transitionResult.failedStepId,\n handlerStepId: transitionResult.errorHandlerStepId,\n },\n })\n continue\n }\n errors.push(\n `Error handler step ${transitionResult.errorHandlerStepId} could not be entered`\n )\n }\n\n if (transitionResult.parkForAttention && transitionResult.failedStepId) {\n await parkInstanceForAttention(\n trx,\n currentInstance,\n transitionResult.failedStepId,\n rejectionMessage\n )\n events.push({\n eventType: 'ERROR_PARKED',\n occurredAt: new Date(),\n data: { failedStepId: transitionResult.failedStepId },\n })\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n logger.error('Transition rejected', {\n instanceId: currentInstance.id,\n workflowId: currentInstance.workflowId,\n fromStepId: currentInstance.currentStepId,\n toStepId: selectedTransition.toStepId,\n err: rejectionMessage,\n })\n errors.push(rejectionMessage)\n\n await completeWorkflow(trx, container, instanceId, 'FAILED', {\n error: rejectionMessage,\n })\n events.push({\n eventType: 'WORKFLOW_FAILED',\n occurredAt: new Date(),\n })\n\n return {\n status: 'FAILED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n }\n\n events.push({\n eventType: 'TRANSITION_EXECUTED',\n occurredAt: new Date(),\n data: {\n fromStepId: selectedTransition.fromStepId,\n toStepId: selectedTransition.toStepId,\n transitionId: selectedTransition.transitionId,\n },\n })\n\n // Spec 2026-06-26: step/stage advances re-emit `started` with the\n // destination stepId so projections can track stage transitions.\n await emitInstanceLifecycleEvent(currentInstance, 'workflows.instance.started', {\n stepId: selectedTransition.toStepId,\n fromStepId: selectedTransition.fromStepId,\n })\n\n if (transitionResult.pausedForActivities) {\n await logWorkflowEvent(trx, {\n workflowInstanceId: currentInstance.id,\n eventType: 'WORKFLOW_WAITING_FOR_ACTIVITIES',\n eventData: {\n pendingActivities: transitionResult.activitiesExecuted?.filter(a => a.async),\n pausedAtTransition: {\n fromStepId: selectedTransition.fromStepId,\n toStepId: selectedTransition.toStepId,\n },\n },\n tenantId: currentInstance.tenantId,\n organizationId: currentInstance.organizationId,\n })\n\n events.push({\n eventType: 'WORKFLOW_WAITING_FOR_ACTIVITIES',\n occurredAt: new Date(),\n data: {\n pendingActivities: transitionResult.activitiesExecuted?.filter(a => a.async),\n },\n })\n\n return {\n status: 'WAITING_FOR_ACTIVITIES',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n // The transition succeeded but the destination step parked the\n // instance (e.g. an INVOKE_AGENT AUTOMATED step enqueued an async\n // agent job and set PAUSED). The token cursor has already advanced to\n // that parked step, so currentInstance.currentStepId is the parked\n // step. Stop advancing until an external signal resumes it.\n if (transitionResult.paused) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n await trx.flush()\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n logger.error('Transition execution failed', {\n instanceId: currentInstance.id,\n workflowId: currentInstance.workflowId,\n fromStepId: currentInstance.currentStepId,\n toStepId: selectedTransition.toStepId,\n err: error,\n })\n errors.push(errorMessage)\n\n events.push({\n eventType: 'TRANSITION_FAILED',\n occurredAt: new Date(),\n data: {\n transitionId: selectedTransition.transitionId,\n error: errorMessage,\n },\n })\n\n await completeWorkflow(trx, container, instanceId, 'FAILED', {\n error: errorMessage,\n details: error instanceof WorkflowExecutionError ? error.details : undefined,\n })\n events.push({\n eventType: 'WORKFLOW_FAILED',\n occurredAt: new Date(),\n })\n\n return {\n status: 'FAILED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n }\n }\n\n errors.push('Maximum execution iterations reached - possible infinite loop')\n return {\n status: 'RUNNING',\n currentStep: instance.currentStepId,\n context: instance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n logger.error('Execution failed', { instanceId, err: error })\n errors.push(errorMessage)\n\n try {\n const instance = await getWorkflowInstanceForExecution(trx, instanceId, { refresh: true })\n if (instance && instance.status === 'RUNNING') {\n instance.status = 'FAILED'\n instance.errorMessage = errorMessage\n instance.errorDetails = error instanceof WorkflowExecutionError ? error.details : undefined\n instance.updatedAt = new Date()\n await writeRunOutcome(trx, instance, 'FAILED')\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_FAILED',\n eventData: { error: errorMessage },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n }\n } catch (updateError) {\n logger.error('Failed to update instance with error state', { instanceId, err: updateError })\n }\n\n throw error\n }\n }\n\n if (typeof transactionalEm.transactional !== 'function') {\n return runExecution(em)\n }\n\n try {\n return await transactionalEm.transactional((trx) => runExecution(trx))\n } catch (error) {\n // The throw has rolled back the execution transaction, discarding the\n // in-transaction FAILED write (and every step/bookkeeping advance) \u2014 which\n // would otherwise leave the instance silently stuck at RUNNING/start (#3632).\n // The in-transaction FAILED write is also futile when the underlying error\n // aborted the Postgres transaction (e.g. an effector issuing bad SQL): every\n // subsequent write on that connection fails. Now that the transaction \u2014 and\n // its PESSIMISTIC_WRITE lock on the instance row \u2014 has been released, durably\n // persist FAILED on an independent fork so the failure is visible and\n // retryable. Restores the #2593 \"persist FAILED\" guarantee even when the\n // whole transaction is discarded. Best-effort: never masks the original error.\n await persistFailedStatusAfterRollback(em, instanceId, error)\n throw error\n }\n}\n\nexport type AgentOutcomeDispatch =\n | { kind: 'routed'; toStepId: string; transitionId?: string; paused?: boolean }\n | { kind: 'parked' }\n | { kind: 'failed'; error: string }\n | { kind: 'default' }\n\n/**\n * Dispatch a resolved agent disposition for whatever step the instance is\n * currently on, or return null when there is no marker to act on.\n *\n * Exported because `sendSignal` advances a resumed instance ITSELF \u2014 it picks\n * the next transition and executes it before handing back to the executor \u2014 so\n * an outcome route wired on a parked agent step has to be honoured there too.\n * Routing it in only one of the two places is how a disposition silently takes\n * the happy path on the human-dispose path while working on the inline one.\n */\nexport async function dispatchAgentOutcomeForCurrentStep(\n em: EntityManager,\n container: AwilixContainer,\n instance: WorkflowInstance,\n definition: OutcomeRoutingDefinitionLike,\n evalContext: { workflowContext: Record<string, unknown>; userId?: string }\n): Promise<AgentOutcomeDispatch | null> {\n const marker = readAgentOutcomeMarker(instance.context, instance.currentStepId ?? '')\n if (!marker) return null\n return await dispatchAgentOutcome(em, container, instance, definition, marker, evalContext)\n}\n\n/**\n * Act on a resolved agent disposition (spec 7.2).\n *\n * The engine-owned marker is consumed here \u2014 cleared before anything else runs \u2014\n * so a route that loops back through the same step cannot re-fire on the old\n * disposition, and so a `default` outcome leaves no residue in the run context.\n *\n * `default` means \"route exactly as this instance always would have\": the step\n * wired no outcome at all, or the outcome is `approved`, which \u00A77.2 renders as\n * the node's ordinary output. Only a step that opted into outcome routing can\n * reach the inheritance branch, which is what keeps this additive.\n */\nasync function dispatchAgentOutcome(\n em: EntityManager,\n container: AwilixContainer,\n instance: WorkflowInstance,\n definition: OutcomeRoutingDefinitionLike,\n marker: WorkflowAgentOutcomeContextEntry,\n evalContext: { workflowContext: Record<string, unknown>; userId?: string }\n): Promise<AgentOutcomeDispatch> {\n const { [WORKFLOW_AGENT_OUTCOME_CONTEXT_KEY]: _consumed, ...remainingContext } =\n (instance.context || {}) as Record<string, unknown>\n instance.context = remainingContext\n instance.updatedAt = new Date()\n await em.flush()\n\n const clearedEvalContext = {\n ...evalContext,\n workflowContext: remainingContext,\n }\n\n const failUnhandled = async (error: string): Promise<AgentOutcomeDispatch> => {\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'OUTCOME_UNHANDLED',\n eventData: { stepId: marker.stepId, outcome: marker.outcome, error },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n return { kind: 'failed', error }\n }\n\n const handling = resolveAgentOutcomeHandling(definition, marker.stepId, marker.outcome)\n if (handling.kind === 'default') return { kind: 'default' }\n\n if (handling.kind === 'route') {\n const toStepId = handling.transition.toStepId\n if (!toStepId) return { kind: 'default' }\n\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'OUTCOME_ROUTED',\n eventData: {\n stepId: marker.stepId,\n outcome: marker.outcome,\n toStepId,\n transitionId: handling.transition.transitionId,\n proposalId: marker.proposalId,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n const transitionHandler = await import('./transition-handler')\n const routed = await transitionHandler.executeTransition(\n em,\n container,\n instance,\n marker.stepId,\n toStepId,\n { ...clearedEvalContext, transitionId: handling.transition.transitionId },\n )\n if (routed.success) {\n return {\n kind: 'routed',\n toStepId,\n transitionId: handling.transition.transitionId,\n paused: routed.paused,\n }\n }\n return await failUnhandled(`Outcome route for \"${marker.outcome}\" could not be followed`)\n }\n\n // `inherit`: an unwired non-approved outcome follows the complete step-error\n // handling contract, including continuation, failure-queue parking and the\n // definition-level handler step.\n const unhandled = `Agent step ${marker.stepId} resolved outcome \"${marker.outcome}\", which is not wired`\n if (handling.handling.kind === 'route') {\n const errorRoute = handling.handling.transition\n if (errorRoute.toStepId) {\n const routed = await followErrorRoute(\n em,\n container,\n instance,\n marker.stepId,\n { transitionId: errorRoute.transitionId, toStepId: errorRoute.toStepId },\n unhandled,\n clearedEvalContext\n )\n if (routed) {\n return {\n kind: 'routed',\n toStepId: errorRoute.toStepId,\n transitionId: errorRoute.transitionId,\n paused: instance.status === 'PAUSED',\n }\n }\n }\n }\n\n if (handling.handling.kind === 'continue') {\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'ERROR_DIRECTIVE_APPLIED',\n eventData: {\n stepId: marker.stepId,\n directive: 'continueWithFallback',\n source: 'agentOutcome',\n hasFallbackValue: handling.handling.fallbackValue !== undefined,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n if (handling.handling.fallbackValue !== undefined) {\n instance.context = {\n ...(instance.context || {}),\n [marker.stepId]: handling.handling.fallbackValue,\n }\n instance.updatedAt = new Date()\n await em.flush()\n }\n return { kind: 'default' }\n }\n\n if (handling.handling.kind === 'park') {\n await parkInstanceForAttention(em, instance, marker.stepId, unhandled)\n return { kind: 'parked' }\n }\n\n if (handling.handling.kind === 'handlerStep') {\n const entered = await enterErrorHandlerStep(\n em,\n container,\n instance,\n marker.stepId,\n handling.handling.stepId,\n unhandled,\n clearedEvalContext.userId,\n )\n if (entered) {\n return {\n kind: 'routed',\n toStepId: handling.handling.stepId,\n paused: instance.status === 'PAUSED',\n }\n }\n }\n\n return await failUnhandled(unhandled)\n}\n\n/**\n * Follow a wired error route out of a failed step (spec 5.9). The failure is\n * published into the run context under `__error` so the handling branch can act\n * on it, then the error transition executes through the normal machinery \u2014 it\n * creates its step instance, runs its activities and logs its events like any\n * other route. Returns false when the route could not be taken, so the caller\n * falls back to the untouched failure path.\n */\nasync function followErrorRoute(\n em: EntityManager,\n container: AwilixContainer,\n instance: WorkflowInstance,\n failedStepId: string,\n errorRoute: { transitionId?: string; toStepId: string },\n error: string,\n evalContext: { workflowContext: Record<string, any>; userId?: string }\n): Promise<boolean> {\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'ERROR_ROUTED',\n eventData: {\n failedStepId,\n toStepId: errorRoute.toStepId,\n transitionId: errorRoute.transitionId,\n error,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n const errorEntry = buildErrorContextEntry(failedStepId, error)\n instance.context = {\n ...(instance.context || {}),\n [WORKFLOW_ERROR_CONTEXT_KEY]: errorEntry,\n }\n instance.updatedAt = new Date()\n await em.flush()\n\n const transitionHandler = await import('./transition-handler')\n const routedResult = await transitionHandler.executeTransition(\n em,\n container,\n instance,\n failedStepId,\n errorRoute.toStepId,\n {\n ...evalContext,\n workflowContext: {\n ...evalContext.workflowContext,\n [WORKFLOW_ERROR_CONTEXT_KEY]: errorEntry,\n },\n transitionId: errorRoute.transitionId,\n },\n )\n\n return routedResult.success === true\n}\n\n/**\n * Enter the definition-level handler STEP (spec 5.9, `errorHandler.stepId`) for\n * a failure no route and no directive handled. The token jumps to the handler\n * step and executes it \u2014 the same cursor-move-plus-`executeStep` shape the\n * branch/timer/signal resumes already use, so no transition record is invented.\n * A failure of the handler step itself resolves to `fail` (the resolver never\n * jumps a step to itself), which is this form's recursion guard.\n */\nasync function enterErrorHandlerStep(\n em: EntityManager,\n container: AwilixContainer,\n instance: WorkflowInstance,\n failedStepId: string,\n handlerStepId: string,\n error: string,\n userId?: string\n): Promise<boolean> {\n const errorEntry = buildErrorContextEntry(failedStepId, error)\n\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'ERROR_HANDLER_STARTED',\n eventData: { failedStepId, handlerStepId, error },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n instance.context = {\n ...(instance.context || {}),\n [WORKFLOW_ERROR_CONTEXT_KEY]: errorEntry,\n }\n instance.currentStepId = handlerStepId\n instance.updatedAt = new Date()\n await em.flush()\n\n const { executeStep } = await import('./step-handler')\n const result = await executeStep(\n em,\n instance,\n handlerStepId,\n {\n workflowContext: {\n ...(instance.context || {}),\n [WORKFLOW_ERROR_CONTEXT_KEY]: errorEntry,\n },\n userId,\n },\n container\n )\n\n return result.status !== 'FAILED'\n}\n\n/**\n * Park a step-through run before the step the author has not released yet.\n *\n * Reuses PAUSED exactly as the failure queue does, and deliberately writes NO\n * `attention` marker: the run is waiting for the author, not for triage, so it\n * must not appear in the failure queue.\n */\nasync function pauseForStepThrough(\n em: EntityManager,\n instance: WorkflowInstance\n): Promise<void> {\n const now = new Date()\n instance.status = 'PAUSED'\n instance.pausedAt = now\n instance.updatedAt = now\n await em.flush()\n\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: STEP_THROUGH_EVENT_TYPE,\n eventData: { stepId: instance.currentStepId },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n}\n\n/**\n * Park an instance for triage instead of failing it \u2014 the `failureQueue` error\n * directive (spec 5.9 \"Send to failure queue\"). Uses the existing PAUSED state\n * plus an engine-owned `metadata.attention` marker; no new instance status and\n * no compensation, because the run is suspended rather than terminated.\n */\nasync function parkInstanceForAttention(\n em: EntityManager,\n instance: WorkflowInstance,\n failedStepId: string,\n error: string\n): Promise<void> {\n const now = new Date()\n instance.status = 'PAUSED'\n instance.pausedAt = now\n instance.errorMessage = error\n instance.metadata = {\n ...(instance.metadata || {}),\n attention: {\n reason: 'ERROR_DIRECTIVE',\n stepId: failedStepId,\n error,\n at: now.toISOString(),\n },\n }\n instance.updatedAt = now\n await em.flush()\n\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'ERROR_PARKED',\n eventData: { failedStepId, error, directive: 'failureQueue' },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n}\n\n/**\n * Durably mark a workflow instance FAILED after its execution transaction has\n * rolled back. MUST run on a fresh fork (a clean connection): the rolled-back\n * transaction may be aborted/poisoned, and its PESSIMISTIC_WRITE lock on the\n * instance row is released only once the transactional callback unwinds, so an\n * in-transaction write here would be discarded or deadlock. Only transitions a\n * still-`RUNNING` instance (leaves CANCELLED/COMPLETED/PAUSED untouched).\n */\nasync function persistFailedStatusAfterRollback(\n em: EntityManager,\n instanceId: string,\n error: unknown,\n): Promise<void> {\n const errorMessage = error instanceof Error ? error.message : String(error)\n const errorDetails = error instanceof WorkflowExecutionError ? error.details : undefined\n const markFailed = async (trx: EntityManager): Promise<void> => {\n const instance = await trx.findOne(\n WorkflowInstance,\n { id: instanceId },\n { lockMode: LockMode.PESSIMISTIC_WRITE },\n )\n if (!instance || instance.status !== 'RUNNING') return\n instance.status = 'FAILED'\n instance.errorMessage = errorMessage\n instance.errorDetails = errorDetails\n instance.updatedAt = new Date()\n await writeRunOutcome(trx, instance, 'FAILED')\n await trx.flush()\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_FAILED',\n eventData: { error: errorMessage },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n await emitInstanceLifecycleEvent(instance, 'workflows.instance.failed')\n }\n try {\n if (typeof (em as { fork?: unknown }).fork !== 'function') return\n const fork = em.fork() as EntityManager & {\n transactional?: <TResult>(callback: (trx: EntityManager) => Promise<TResult>) => Promise<TResult>\n }\n if (typeof fork.transactional === 'function') {\n await fork.transactional((trx) => markFailed(trx))\n } else {\n await markFailed(fork)\n }\n } catch (persistError) {\n logger.error('failed to durably persist FAILED status after rollback', {\n instanceId,\n error: persistError instanceof Error ? persistError.message : String(persistError),\n })\n }\n}\n\n/**\n * Write the run's terminal VERDICT onto the instance, and guarantee it has a\n * terminal timestamp.\n *\n * The ONE write site, so `outcome` cannot be assembled ad hoc per exit point:\n * every caller hands over the terminal status and the pure\n * `resolveRunOutcome` decides from the evidence the run recorded. Called before\n * the flush that persists the terminal status, so status and verdict land in the\n * same UPDATE and no reader can observe one without the other.\n *\n * The timestamp backstop closes a real gap. `compensation-handler` flips the\n * status to COMPENSATED (or back to FAILED on a partial compensation) and\n * `completeWorkflow` RETURNS before its own `completedAt` assignment on that\n * path, so a compensated run had no terminal instant at all \u2014 it could be\n * attributed to no KPI window and its duration was unmeasurable. Every other\n * path already assigns one, so this only ever fills a hole; it never moves an\n * instant that was already recorded, and CANCELLED is excluded because\n * `cancelledAt` is its terminal instant.\n */\nasync function writeRunOutcome(\n em: EntityManager,\n instance: WorkflowInstance,\n terminalStatus: string,\n): Promise<void> {\n const evidence = await collectRunOutcomeEvidence(em, instance, terminalStatus)\n instance.outcome = resolveRunOutcome(evidence)\n\n if (terminalStatus !== 'CANCELLED' && !instance.completedAt) {\n instance.completedAt = new Date()\n }\n}\n\n/**\n * Complete a workflow instance with final status\n *\n * @param em - Entity manager\n * @param container\n * @param instanceId - Workflow instance ID\n * @param status - Final status (COMPLETED, FAILED, CANCELLED)\n * @param result - Optional result data\n */\nexport async function completeWorkflow(\n em: EntityManager,\n container: AwilixContainer,\n instanceId: string,\n status: 'COMPLETED' | 'FAILED' | 'CANCELLED',\n result?: any\n): Promise<void> {\n const instance = await getWorkflowInstance(em, instanceId)\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n // Workflow-level error handler (spec 5.9) \u2014 scheduled BEFORE compensation so\n // the handler observes the state that failed rather than the rolled-back one,\n // and so it still runs when compensation throws (that block swallows errors\n // and returns early). Executed out of band by the worker; the\n // ERROR_HANDLER_SCHEDULED event is written here, inside this transaction.\n if (status === 'FAILED') {\n await scheduleWorkflowErrorHandler(em, instance, {\n failedStepId: result?.failedStepId ?? instance.currentStepId,\n error: result?.error,\n details: result?.details,\n })\n }\n\n // Trigger compensation if workflow failed and has compensatable activities (Phase 8.2)\n if (status === 'FAILED') {\n const definition = await findDefinitionForInstance(em, instance)\n\n if (definition && checkIfCompensationNeeded(definition)) {\n try {\n\n // Set error message before compensation\n if (result?.error) {\n instance.errorMessage = result.error\n instance.errorDetails = result.details\n await em.flush()\n }\n\n const compensationResult = await compensateWorkflow(\n em,\n container,\n instance,\n definition,\n {\n continueOnError: true // Best-effort compensation\n }\n )\n\n logger.info('Compensation finished', {\n status: compensationResult.status,\n compensatedActivities: compensationResult.compensatedActivities,\n totalActivities: compensationResult.totalActivities,\n })\n\n // Note: instance status already updated by compensateWorkflow\n // It will be COMPENSATED or remain FAILED. This branch RETURNS, so the\n // verdict is written here rather than at the shared tail below \u2014 same\n // resolver, same evidence, one more call site than the ideal one.\n await writeRunOutcome(em, instance, instance.status)\n await em.flush()\n\n // A compensated/failed child must still resume its parent SUB_WORKFLOW\n // step \u2014 otherwise a parent parked on this child stays PAUSED forever.\n // From the parent's perspective the sub-workflow did not succeed, so this\n // mirrors the normal-path enqueue below but always signals FAILED.\n await enqueueSubWorkflowParentResume(instance, 'FAILED')\n // Terminal signal for external projections: the run did not succeed,\n // regardless of whether compensation left it COMPENSATED or FAILED\n // (payload `status` carries the actual post-compensation status).\n await emitInstanceLifecycleEvent(instance, 'workflows.instance.failed')\n return\n } catch (error: any) {\n logger.error('Compensation failed with exception', { err: error })\n // Continue to mark workflow as failed\n }\n }\n }\n\n // Original completion logic (no compensation needed or status is COMPLETED/CANCELLED)\n const now = new Date()\n instance.status = status\n instance.updatedAt = now\n\n switch (status) {\n case 'COMPLETED':\n instance.completedAt = now\n if (result) {\n instance.context = { ...instance.context, __result: result }\n }\n break\n\n case 'FAILED':\n instance.completedAt = now\n if (result?.error) {\n instance.errorMessage = result.error\n instance.errorDetails = result.details\n }\n break\n\n case 'CANCELLED':\n instance.cancelledAt = now\n break\n }\n\n await writeRunOutcome(em, instance, status)\n\n await em.flush()\n\n // Log completion event\n const eventType =\n status === 'COMPLETED'\n ? 'WORKFLOW_COMPLETED'\n : status === 'FAILED'\n ? 'WORKFLOW_FAILED'\n : 'WORKFLOW_CANCELLED'\n\n await logWorkflowEvent(em, {\n workflowInstanceId: instanceId,\n eventType,\n eventData: result || {},\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n await emitInstanceLifecycleEvent(\n instance,\n status === 'COMPLETED'\n ? 'workflows.instance.completed'\n : status === 'FAILED'\n ? 'workflows.instance.failed'\n : 'workflows.instance.cancelled'\n )\n\n // If this instance is a child of a parked SUB_WORKFLOW step, enqueue a job to\n // resume the parent on the worker's own connection (never inline inside the\n // child's transaction \u2014 lock-ordering hazard). The worker guard skips the job\n // when the parent never parked (fully-synchronous fast path).\n if (status === 'COMPLETED' || status === 'FAILED') {\n await enqueueSubWorkflowParentResume(instance, status)\n }\n}\n\n/**\n * Enqueue a `resume_subworkflow_parent` job when a terminating instance carries a\n * parent linkage. Best-effort: a queue hiccup must not undo the just-persisted\n * terminal status, so failures are logged rather than thrown. The small delay\n * lets the parent's PAUSED flush become visible before the worker runs.\n */\nasync function enqueueSubWorkflowParentResume(\n instance: WorkflowInstance,\n childStatus: 'COMPLETED' | 'FAILED'\n): Promise<void> {\n const labels = instance.metadata?.labels\n const parentInstanceId = labels?.parentInstanceId\n const parentStepId = labels?.parentStepId\n const parentStepInstanceId = labels?.parentStepInstanceId\n if (!parentInstanceId || !parentStepId || !parentStepInstanceId) return\n\n try {\n const { createModuleQueue } = await import('@open-mercato/queue')\n const { WORKFLOW_ACTIVITIES_QUEUE_NAME } = await import('./activity-queue-types')\n const { INVOKE_AGENT_ENQUEUE_DELAY_MS } = await import('./activity-executor')\n\n const queue = createModuleQueue<WorkflowActivityJob>(WORKFLOW_ACTIVITIES_QUEUE_NAME, {\n concurrency: parseInt(process.env.WORKFLOW_WORKER_CONCURRENCY || '5'),\n })\n\n const job: WorkflowActivityJobResumeSubWorkflowParent = {\n kind: 'resume_subworkflow_parent',\n workflowInstanceId: parentInstanceId,\n parentInstanceId,\n parentStepId,\n parentStepInstanceId,\n childInstanceId: instance.id,\n childStatus,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n }\n await queue.enqueue(job, { delayMs: INVOKE_AGENT_ENQUEUE_DELAY_MS })\n } catch (error) {\n logger.error('failed to enqueue parent-resume job', {\n childInstanceId: instance.id,\n parentInstanceId,\n error: error instanceof Error ? error.message : String(error),\n })\n }\n}\n\n/**\n * Resume workflow after async activities complete\n *\n * Called by the activity worker after all async activities finish execution.\n * Checks if all activities are done, merges outputs into context, and resumes execution.\n *\n * @param em - Entity manager\n * @param container - DI container\n * @param instanceId - Workflow instance ID\n */\nexport async function resumeWorkflowAfterActivities(\n em: EntityManager,\n container: AwilixContainer,\n instanceId: string,\n branchInstanceId?: string | null\n): Promise<void> {\n const transactionalEm = em as EntityManager & {\n transactional?: <TResult>(callback: (trx: EntityManager) => Promise<TResult>) => Promise<TResult>\n }\n\n // Branch-scoped async resume: the instance is FORKED and the branch (not the\n // instance) is WAITING_FOR_ACTIVITIES. Resume just that branch, then let the\n // interleaved loop continue. Missing branchInstanceId \u2192 legacy instance path.\n if (branchInstanceId) {\n const { resumeBranchAfterActivities } = await import('./parallel-handler')\n const branchResume = typeof transactionalEm.transactional === 'function'\n ? await transactionalEm.transactional((trx) => resumeBranchAfterActivities(trx, container, instanceId, branchInstanceId))\n : await resumeBranchAfterActivities(em, container, instanceId, branchInstanceId)\n if (branchResume.continueExecution) {\n await executeWorkflow(em, container, instanceId)\n }\n return\n }\n\n const runResume = async (trx: EntityManager): Promise<{ continueExecution: boolean }> => {\n const instance = await trx.findOne(WorkflowInstance, {\n id: instanceId,\n status: 'WAITING_FOR_ACTIVITIES',\n }, { lockMode: LockMode.PESSIMISTIC_WRITE })\n\n if (!instance) {\n throw new Error('Workflow instance not waiting for activities')\n }\n\n const pendingJobIds = (instance.context._pendingAsyncActivities as any[]) || []\n\n const completedActivities = await trx.count(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_COMPLETED',\n eventData: { async: true },\n })\n\n const failedActivities = await trx.count(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_FAILED',\n eventData: { async: true },\n })\n\n const totalProcessed = completedActivities + failedActivities\n\n if (totalProcessed < pendingJobIds.length) {\n throw new Error('Activities still pending')\n }\n\n if (failedActivities > 0) {\n const failedEvents = await trx.find(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_FAILED',\n eventData: { async: true },\n })\n\n instance.status = 'FAILED'\n instance.errorMessage = `${failedActivities} async activities failed`\n instance.errorDetails = {\n failedActivities: failedEvents.map(e => ({\n activityId: e.eventData.activityId,\n error: e.eventData.error,\n jobId: e.eventData.jobId,\n })),\n }\n await writeRunOutcome(trx, instance, 'FAILED')\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_FAILED',\n eventData: {\n reason: 'Async activities failed',\n failedActivities: instance.errorDetails.failedActivities,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return { continueExecution: false }\n }\n\n const completedEvents = await trx.find(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_COMPLETED',\n eventData: { async: true },\n })\n\n for (const event of completedEvents) {\n if (event.eventData.output) {\n instance.context = {\n ...instance.context,\n [`${event.eventData.activityId}_result`]: event.eventData.output,\n }\n }\n }\n\n delete instance.context._pendingAsyncActivities\n\n const pendingTransition = instance.pendingTransition\n\n if (!pendingTransition) {\n logger.warn('No pending transition found during resume')\n instance.status = 'RUNNING'\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_RESUMED',\n eventData: {\n reason: 'All async activities completed',\n completedActivities: completedActivities,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return { continueExecution: true }\n }\n\n logger.debug('Completing pending transition', {\n toStepId: pendingTransition.toStepId,\n fromStepId: instance.currentStepId,\n })\n\n const definition = await findDefinitionForInstance(trx, instance)\n if (!definition) {\n throw new WorkflowExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n const step = definition.definition.steps.find(s => s.stepId === pendingTransition.toStepId)\n\n instance.currentStepId = pendingTransition.toStepId\n instance.status = 'RUNNING'\n instance.pendingTransition = null\n instance.updatedAt = new Date()\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instance.id,\n eventType: 'STEP_ENTERED',\n eventData: {\n stepId: pendingTransition.toStepId,\n stepName: step?.stepName,\n stepType: step?.stepType,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_RESUMED',\n eventData: {\n reason: 'Async activities completed, resuming pending transition',\n completedActivities: completedActivities,\n completedTransitionTo: pendingTransition.toStepId,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // The async-resume path runs inside a worker, so it re-resolves the actor\n // from the definition exactly as the main loop does \u2014 otherwise a granted\n // workflow would revert to the starting user's identity the moment one of\n // its activities went async.\n const resumeDefinition = await findDefinitionForInstance(trx, instance)\n const { executeStep } = await import('./step-handler')\n await executeStep(\n trx,\n instance,\n pendingTransition.toStepId,\n {\n workflowContext: instance.context || {},\n userId: resumeDefinition\n ? await resolveRunActorUserId(trx, resumeDefinition, undefined, instance)\n : resolveWorkflowExecutionUserId(undefined, instance),\n },\n container\n )\n\n return { continueExecution: true }\n }\n\n const resumeResult = typeof transactionalEm.transactional === 'function'\n ? await transactionalEm.transactional((trx) => runResume(trx))\n : await runResume(em)\n\n if (resumeResult.continueExecution) {\n await executeWorkflow(em, container, instanceId)\n }\n}\n\n/**\n * Check if workflow definition has any compensatable activities\n */\nfunction checkIfCompensationNeeded(definition: WorkflowDefinition): boolean {\n // Check if any activities have compensation defined\n for (const transition of definition.definition.transitions) {\n if (transition.activities) {\n for (const activity of transition.activities) {\n if (activity.compensation?.activityId) {\n return true\n }\n }\n }\n }\n\n // Check root-level activities (legacy)\n if (definition.definition.activities) {\n for (const activity of definition.definition.activities) {\n if (activity.compensation?.activityId) {\n return true\n }\n }\n }\n\n return false\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Get workflow instance by ID.\n *\n * SECURITY: this helper is NOT tenant-scoped. It is an internal lookup whose\n * callers are expected to have resolved and enforced the scope already. Never\n * reach it directly from an HTTP handler \u2014 use a scoped query (see\n * `updateWorkflowContextScoped`) so a cross-tenant id cannot resolve.\n *\n * @param em - Entity manager\n * @param instanceId - Workflow instance ID\n * @returns Workflow instance or null if not found\n */\nexport async function getWorkflowInstance(\n em: EntityManager,\n instanceId: string\n): Promise<WorkflowInstance | null> {\n return em.findOne(WorkflowInstance, { id: instanceId })\n}\n\nasync function getWorkflowInstanceForExecution(\n em: EntityManager,\n instanceId: string,\n options?: { refresh?: boolean }\n): Promise<WorkflowInstance | null> {\n return em.findOne(\n WorkflowInstance,\n { id: instanceId },\n {\n lockMode: LockMode.PESSIMISTIC_WRITE,\n ...(options?.refresh ? { refresh: true } : {}),\n }\n )\n}\n\n/**\n * Update workflow context with new data.\n *\n * SECURITY: builds on the UNSCOPED {@link getWorkflowInstance} and therefore\n * performs no tenant/organization filtering of its own. It is preserved as-is\n * for backward compatibility (it is a DI-exposed surface). HTTP handlers MUST\n * use {@link updateWorkflowContextScoped} instead.\n *\n * @param em - Entity manager\n * @param instanceId - Workflow instance ID\n * @param updates - Context updates (merged with existing context)\n */\nexport async function updateWorkflowContext(\n em: EntityManager,\n instanceId: string,\n updates: Record<string, any>\n): Promise<void> {\n const instance = await getWorkflowInstance(em, instanceId)\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n instance.context = {\n ...instance.context,\n ...updates,\n }\n instance.updatedAt = new Date()\n\n await em.flush()\n}\n\n/**\n * Context keys the engine owns. A caller-supplied patch may never write them:\n * `__result` carries the terminal workflow result, `_pendingAsyncActivities`\n * tracks in-flight async activity jobs, and `__park` marks a parked agent step.\n * Overwriting any of them would corrupt a running instance, so they are\n * rejected rather than silently dropped.\n */\nexport const RESERVED_WORKFLOW_CONTEXT_KEYS: readonly string[] = [\n '__result',\n '_pendingAsyncActivities',\n '__park',\n WORKFLOW_ERROR_CONTEXT_KEY,\n]\n\nexport function findReservedContextKeys(updates: Record<string, unknown>): string[] {\n return Object.keys(updates).filter((key) => RESERVED_WORKFLOW_CONTEXT_KEYS.includes(key))\n}\n\nexport interface UpdateWorkflowContextScopedOptions {\n instanceId: string\n tenantId: string\n organizationId: string\n updates: Record<string, unknown>\n /**\n * Optional version check, awaited with the freshly loaded row's `updatedAt`\n * before the patch is applied. HTTP callers pass\n * `enforceCommandOptimisticLockWithGuards` here so a stale write 409s instead\n * of silently clobbering a concurrent context change.\n */\n assertVersion?: (current: Date | null | undefined) => void | Promise<void>\n}\n\n/**\n * Tenant/organization-scoped sibling of {@link updateWorkflowContext}: the\n * scope is part of the lookup, so a cross-tenant instance id resolves to\n * nothing and the caller returns a 404 rather than reading or writing another\n * tenant's run. Shallow merge, consistent with the legacy helper.\n */\nexport async function updateWorkflowContextScoped(\n em: EntityManager,\n options: UpdateWorkflowContextScopedOptions\n): Promise<WorkflowInstance> {\n const { instanceId, tenantId, organizationId, updates, assertVersion } = options\n\n const reserved = findReservedContextKeys(updates)\n if (reserved.length > 0) {\n throw new WorkflowExecutionError(\n `Reserved workflow context keys cannot be written: ${reserved.join(', ')}`,\n 'RESERVED_CONTEXT_KEY',\n { instanceId, reserved }\n )\n }\n\n const instance = await findOneWithDecryption(\n em as PostgreSqlEntityManager,\n WorkflowInstance,\n { id: instanceId, tenantId, organizationId },\n undefined,\n { tenantId, organizationId }\n )\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n if (instance.status !== 'RUNNING' && instance.status !== 'PAUSED' && instance.status !== 'FORKED') {\n throw new WorkflowExecutionError(\n `Workflow instance is not accepting context updates: ${instance.status}`,\n 'INSTANCE_NOT_UPDATABLE',\n { instanceId, status: instance.status }\n )\n }\n\n if (assertVersion) await assertVersion(instance.updatedAt)\n\n instance.context = {\n ...instance.context,\n ...updates,\n }\n instance.updatedAt = new Date()\n\n await em.flush()\n\n return instance\n}\n\n// findWorkflowDefinition is imported from ./find-definition\n\ntype InstanceLifecycleEventId =\n | 'workflows.instance.created'\n | 'workflows.instance.started'\n | 'workflows.instance.completed'\n | 'workflows.instance.failed'\n | 'workflows.instance.cancelled'\n\n/**\n * Publish a declared `workflows.instance.*` lifecycle event to the event bus,\n * alongside (never instead of) the internal `WorkflowEvent` audit row. Delivery\n * is at-least-once and consumers must be idempotent; a bus failure must never\n * break workflow execution, so this is strictly best-effort.\n */\nasync function emitInstanceLifecycleEvent(\n instance: WorkflowInstance,\n eventId: InstanceLifecycleEventId,\n extra?: Record<string, unknown>\n): Promise<void> {\n try {\n await emitWorkflowsEvent(\n eventId,\n {\n id: instance.id,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n workflowId: instance.workflowId,\n version: instance.version,\n status: instance.status,\n stepId: instance.currentStepId ?? null,\n ...extra,\n },\n { persistent: true }\n )\n } catch (error) {\n logger.error('failed to emit workflow event', {\n eventId,\n instanceId: instance.id,\n error: error instanceof Error ? error.message : String(error),\n })\n }\n}\n\n/**\n * Log workflow event to event sourcing table\n *\n * @param em - Entity manager\n * @param event - Event data\n */\nasync function logWorkflowEvent(\n em: EntityManager,\n event: {\n workflowInstanceId: string\n stepInstanceId?: string\n eventType: string\n eventData: any\n userId?: string\n tenantId: string\n organizationId: string\n }\n): Promise<WorkflowEvent> {\n const workflowEvent = em.create(WorkflowEvent, {\n ...event,\n occurredAt: new Date(),\n })\n\n await em.persist(workflowEvent).flush()\n return workflowEvent\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Workflows Module - Workflow Executor Service\n *\n * Main orchestrator for workflow execution. Handles workflow lifecycle:\n * - Starting workflow instances from definitions\n * - Executing workflow steps and transitions\n * - Completing workflows with final status\n * - Triggering compensation on failure\n *\n * Functional API (no classes) following Open Mercato conventions.\n */\n\nimport { EntityManager, LockMode } from '@mikro-orm/core'\nimport type { EntityManager as PostgreSqlEntityManager } from '@mikro-orm/postgresql'\nimport type { AwilixContainer } from 'awilix'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport {\n WorkflowDefinition,\n WorkflowInstance,\n WorkflowEvent,\n type WorkflowInstanceStatus,\n type WorkflowInstanceErrorHandlerMetadata,\n} from '../data/entities'\nimport { compensateWorkflow } from './compensation-handler'\nimport {\n ASYNC_ACTIVITY_OUTCOME_EVENT_TYPES,\n readPendingAsyncJobIds,\n resolveAsyncActivityWait,\n} from './async-activity-wait'\nimport { WORKFLOW_ENGINE_VERSION, isEngineVersionSupported } from './engine-version'\nimport {\n WORKFLOW_ERROR_CONTEXT_KEY,\n buildErrorContextEntry,\n} from './error-routing'\nimport { excludeNonNormalTransitions } from './route-kinds'\nimport {\n WORKFLOW_AGENT_OUTCOME_CONTEXT_KEY,\n readAgentOutcomeMarker,\n resolveAgentOutcomeHandling,\n type OutcomeRoutingDefinitionLike,\n type WorkflowAgentOutcomeContextEntry,\n} from './outcome-routing'\nimport { scheduleWorkflowErrorHandler } from './error-handler'\nimport { resolveRunOutcome } from './run-outcome'\nimport { collectRunOutcomeEvidence } from './run-outcome-evidence'\nimport { findWorkflowDefinition, findDefinitionForInstance } from './find-definition'\nimport { resolveWorkflowDefinitionExecutionUserId } from './definition-grant'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { emitWorkflowsEvent } from '../events'\nimport { DRY_RUN_EVENT_TYPES } from './dry-run'\nimport {\n STEP_THROUGH_EVENT_TYPE,\n consumeStepThroughRelease,\n isStepThroughArmed,\n shouldPauseForStepThrough,\n} from './step-through'\nimport type {\n WorkflowActivityJob,\n WorkflowActivityJobResumeSubWorkflowParent,\n} from './activity-queue-types'\n\nconst logger = createLogger('workflows')\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface StartWorkflowOptions {\n workflowId: string\n version?: number // Default to latest enabled version\n initialContext?: Record<string, any>\n correlationKey?: string\n metadata?: {\n entityType?: string\n entityId?: string\n initiatedBy?: string\n labels?: Record<string, string>\n // Set by the workflow-level error handler when it starts a handler run, so\n // the depth guard travels with the child instance (spec 5.9).\n errorHandler?: WorkflowInstanceErrorHandlerMetadata | null\n }\n /**\n * Run this instance as a side-effect-free simulation (spec section 8.2).\n *\n * It is durable state on the row rather than a per-call argument because a\n * run outlives the call that started it: it parks on a signal, resumes from a\n * worker, is advanced by a task completion. Anything that only lived on this\n * options object would stop protecting the run the moment it suspended.\n */\n isDryRun?: boolean\n tenantId: string\n organizationId: string\n}\n\nexport interface ExecutionContext {\n userId?: string\n /**\n * @deprecated Never read, and never was. Dry-run state lives on\n * `WorkflowInstance.isDryRun` (spec section 8.2) because a per-execution flag\n * cannot survive the instance parking on a signal and resuming inside a\n * worker \u2014 which is exactly when a leak would happen. Kept as an inert field\n * for one minor per `BACKWARD_COMPATIBILITY.md`; pass `isDryRun` to\n * `startWorkflow` instead.\n */\n dryRun?: boolean\n timeout?: number\n}\n\nexport interface ExecutionResult {\n status: WorkflowInstanceStatus\n currentStep: string\n context: Record<string, any>\n events: WorkflowEventSummary[]\n errors?: string[]\n executionTime: number\n}\n\nexport interface WorkflowEventSummary {\n eventType: string\n occurredAt: Date\n data?: any\n}\n\nfunction normalizeWorkflowUserId(value: unknown): string | null {\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n if (!trimmed || trimmed.startsWith('trigger:')) return null\n return trimmed\n}\n\nfunction resolveWorkflowExecutionUserId(\n context: ExecutionContext | undefined,\n instance: WorkflowInstance,\n): string | undefined {\n return (\n normalizeWorkflowUserId(context?.userId) ??\n normalizeWorkflowUserId(instance.metadata?.initiatedBy) ??\n undefined\n )\n}\n\n/**\n * The identity this run advances under.\n *\n * A definition declaring `grantedFeatures` ALWAYS acts as its own least-\n * privilege principal, so a run started by an admin cannot silently gain the\n * admin's powers and an event-triggered run (which has no actor at all) gets a\n * real one. Everything else keeps the historic borrow-the-starting-user\n * behaviour, byte-for-byte.\n */\nasync function resolveRunActorUserId(\n em: EntityManager,\n definition: WorkflowDefinition,\n context: ExecutionContext | undefined,\n instance: WorkflowInstance,\n): Promise<string | undefined> {\n const fallback = resolveWorkflowExecutionUserId(context, instance)\n const actor = await resolveWorkflowDefinitionExecutionUserId(\n em as unknown as PostgreSqlEntityManager,\n definition,\n fallback,\n )\n return actor ?? undefined\n}\n\nexport class WorkflowExecutionError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: any\n ) {\n super(message)\n this.name = 'WorkflowExecutionError'\n }\n}\n\n// ============================================================================\n// Main Orchestration Functions\n// ============================================================================\n\n/**\n * Start a new workflow instance from a definition\n *\n * @param em - Entity manager for database operations\n * @param options - Workflow start options\n * @returns Created workflow instance\n * @throws WorkflowExecutionError if definition not found or validation fails\n */\nexport async function startWorkflow(\n em: EntityManager,\n options: StartWorkflowOptions\n): Promise<WorkflowInstance> {\n const {\n workflowId,\n version,\n initialContext = {},\n correlationKey,\n metadata,\n isDryRun = false,\n tenantId,\n organizationId,\n } = options\n\n // Find workflow definition\n const definition = await findWorkflowDefinition(em, {\n workflowId,\n version,\n tenantId,\n organizationId,\n })\n\n if (!definition) {\n throw new WorkflowExecutionError(\n `Workflow definition not found: ${workflowId}${version ? ` v${version}` : ''}`,\n 'DEFINITION_NOT_FOUND',\n { workflowId, version }\n )\n }\n\n if (!definition.enabled) {\n throw new WorkflowExecutionError(\n `Workflow definition is disabled: ${workflowId}`,\n 'DEFINITION_DISABLED',\n { workflowId, version: definition.version }\n )\n }\n\n // Forward-compatibility guard: a definition authored against a newer engine\n // is refused outright rather than executed with unknown step types treated\n // as no-ops (spec section 5.8).\n const minEngineVersion = definition.metadata?.minEngineVersion\n if (!isEngineVersionSupported(minEngineVersion)) {\n throw new WorkflowExecutionError(\n `Workflow definition requires engine version ${minEngineVersion}, this engine is version ${WORKFLOW_ENGINE_VERSION}`,\n 'ENGINE_VERSION_TOO_OLD',\n { workflowId, version: definition.version, minEngineVersion, engineVersion: WORKFLOW_ENGINE_VERSION }\n )\n }\n\n // Validate definition has required steps\n const { steps, transitions } = definition.definition\n if (!steps || steps.length < 2) {\n throw new WorkflowExecutionError(\n 'Workflow definition must have at least START and END steps',\n 'INVALID_DEFINITION',\n { workflowId, stepsCount: steps?.length || 0 }\n )\n }\n\n if (!transitions || transitions.length < 1) {\n throw new WorkflowExecutionError(\n 'Workflow definition must have at least one transition',\n 'INVALID_DEFINITION',\n { workflowId, transitionsCount: transitions?.length || 0 }\n )\n }\n\n // Find START step\n const startStep = steps.find((s: any) => s.stepType === 'START')\n if (!startStep) {\n throw new WorkflowExecutionError(\n 'Workflow definition must have a START step',\n 'INVALID_DEFINITION',\n { workflowId }\n )\n }\n\n // Validate START step pre-conditions if defined\n if (startStep.preConditions && startStep.preConditions.length > 0) {\n const { validateWorkflowStart } = await import('./start-validator')\n\n const validationResult = await validateWorkflowStart(em, {\n workflowId,\n version: definition.version,\n context: initialContext,\n tenantId,\n organizationId,\n })\n\n if (!validationResult.canStart) {\n throw new WorkflowExecutionError(\n `Workflow start pre-conditions failed: ${validationResult.errors.map(e => e.message).join('; ')}`,\n 'START_PRE_CONDITIONS_FAILED',\n {\n workflowId,\n errors: validationResult.errors,\n validatedRules: validationResult.validatedRules,\n }\n )\n }\n }\n\n // Create workflow instance\n const now = new Date()\n const instance = em.create(WorkflowInstance, {\n definitionId: definition.id,\n workflowId: definition.workflowId,\n version: definition.version,\n status: 'RUNNING',\n currentStepId: startStep.stepId,\n context: initialContext,\n correlationKey,\n metadata,\n startedAt: now,\n retryCount: 0,\n isDryRun,\n tenantId,\n organizationId,\n createdAt: now,\n updatedAt: now,\n })\n\n await em.persist(instance).flush()\n\n // Log WORKFLOW_STARTED event\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'WORKFLOW_STARTED',\n eventData: {\n workflowId: instance.workflowId,\n version: instance.version,\n startStepId: startStep.stepId,\n initialContext,\n metadata,\n },\n userId: metadata?.initiatedBy,\n tenantId,\n organizationId,\n })\n\n if (isDryRun) {\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: DRY_RUN_EVENT_TYPES.started,\n eventData: { workflowId: instance.workflowId, version: instance.version },\n userId: metadata?.initiatedBy,\n tenantId,\n organizationId,\n })\n }\n\n await emitInstanceLifecycleEvent(instance, 'workflows.instance.created')\n await emitInstanceLifecycleEvent(instance, 'workflows.instance.started')\n\n return instance\n}\n\n/**\n * Execute a workflow instance\n *\n * Main execution loop that processes steps and transitions until:\n * - Workflow completes (reaches END step)\n * - Workflow waits (USER_TASK, SIGNAL, TIMER)\n * - Workflow fails (error occurs)\n * - Timeout is reached\n *\n * @param em - Entity manager\n * @param container - DI container (for activity execution and other services)\n * @param instanceId - Workflow instance ID\n * @param context - Execution context (userId, dryRun, timeout)\n * @returns Execution result with status and events\n */\nexport async function executeWorkflow(\n em: EntityManager,\n container: AwilixContainer,\n instanceId: string,\n context?: ExecutionContext\n): Promise<ExecutionResult> {\n const startTime = Date.now()\n const transactionalEm = em as EntityManager & {\n transactional?: <TResult>(\n callback: (trx: EntityManager) => Promise<TResult>,\n ) => Promise<TResult>\n }\n\n const runExecution = async (trx: EntityManager): Promise<ExecutionResult> => {\n const events: WorkflowEventSummary[] = []\n const errors: string[] = []\n\n try {\n const instance = await getWorkflowInstanceForExecution(trx, instanceId)\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n if (instance.status === 'COMPLETED') {\n return {\n status: 'COMPLETED',\n currentStep: instance.currentStepId,\n context: instance.context,\n events: [],\n executionTime: 0,\n }\n }\n\n if (instance.status === 'CANCELLED') {\n throw new WorkflowExecutionError(\n 'Cannot execute cancelled workflow',\n 'WORKFLOW_CANCELLED',\n { instanceId, status: instance.status }\n )\n }\n\n const definition = await findDefinitionForInstance(trx, instance)\n\n if (!definition) {\n throw new WorkflowExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n const maxIterations = 100\n let iterations = 0\n const executionUserId = await resolveRunActorUserId(trx, definition, context, instance)\n\n while (iterations < maxIterations) {\n iterations++\n\n const currentInstance = await getWorkflowInstanceForExecution(trx, instanceId, { refresh: iterations > 1 })\n if (!currentInstance) {\n throw new WorkflowExecutionError(\n 'Instance not found during execution',\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n // Parallel execution: while the instance is FORKED, drive the branches.\n if (currentInstance.status === 'FORKED') {\n const { advanceBranches } = await import('./parallel-handler')\n const branchResult = await advanceBranches(trx, container, currentInstance, definition, {\n userId: executionUserId,\n })\n\n if (branchResult.outcome === 'joined') {\n // Instance resumed at the post-join step; continue single-token.\n continue\n }\n\n if (branchResult.outcome === 'failed') {\n errors.push(branchResult.error || 'Parallel branch failed')\n await completeWorkflow(trx, container, instanceId, 'FAILED', {\n error: branchResult.error || 'Parallel branch failed',\n })\n return {\n status: 'FAILED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n }\n\n // 'waiting' \u2014 all branches paused for external resume (task/signal/timer/async).\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n // Defense in depth: a prior step parked the instance (e.g. an\n // INVOKE_AGENT AUTOMATED step set PAUSED, or a transition set\n // WAITING_FOR_ACTIVITIES). Every resume path (sendSignal,\n // resumeWorkflowAfterActivities) flips status back to RUNNING before\n // re-entering, so a PAUSED/WAITING_FOR_ACTIVITIES status here means an\n // external completion is still pending \u2014 stop advancing.\n if (currentInstance.status === 'PAUSED' || currentInstance.status === 'WAITING_FOR_ACTIVITIES') {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const currentStep = definition.definition.steps.find(\n (s: any) => s.stepId === currentInstance.currentStepId\n )\n\n // Step-through (spec section 8.2). An instance-level PAUSED between\n // steps \u2014 no new instance status and no new step status, so the state\n // machines are untouched. The marker is a RELEASE TOKEN for exactly one\n // step id, so replaying this loop after a crash cannot run a step the\n // author never released, and a double Continue cannot run two.\n if (\n shouldPauseForStepThrough(\n currentInstance,\n currentInstance.currentStepId,\n currentStep?.stepType\n )\n ) {\n await pauseForStepThrough(trx, currentInstance)\n events.push({\n eventType: STEP_THROUGH_EVENT_TYPE,\n occurredAt: new Date(),\n data: { stepId: currentInstance.currentStepId },\n })\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n if (isStepThroughArmed(currentInstance)) {\n // The released step is about to run: burn the token now so the cursor\n // landing on the NEXT step pauses, whatever route it takes.\n currentInstance.metadata = {\n ...(currentInstance.metadata || {}),\n stepThrough: consumeStepThroughRelease(),\n }\n currentInstance.updatedAt = new Date()\n await trx.flush()\n }\n\n if (currentStep?.stepType === 'END') {\n await completeWorkflow(trx, container, instanceId, 'COMPLETED')\n events.push({\n eventType: 'WORKFLOW_COMPLETED',\n occurredAt: new Date(),\n })\n\n return {\n status: 'COMPLETED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n if (\n currentStep?.stepType === 'USER_TASK' ||\n currentStep?.stepType === 'WAIT_FOR_SIGNAL' ||\n currentStep?.stepType === 'WAIT_FOR_TIMER'\n ) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n // Outcome routing (spec 7.2). An agent step that resolved a disposition\n // leaves an engine-owned marker; a wired outcome route is followed\n // declaratively instead of via a condition matching a context string.\n // `default` \u2014 the marker's absence, or a step that wired no outcome at\n // all \u2014 falls straight through to the normal routing below, which is the\n // whole of the backward-compatibility guarantee.\n const outcomeMarker = readAgentOutcomeMarker(\n currentInstance.context,\n currentInstance.currentStepId ?? '',\n )\n if (outcomeMarker) {\n const dispatched = await dispatchAgentOutcome(\n trx,\n container,\n currentInstance,\n definition.definition,\n outcomeMarker,\n { workflowContext: currentInstance.context, userId: executionUserId },\n )\n if (dispatched.kind === 'routed') {\n events.push({\n eventType: 'OUTCOME_ROUTED',\n occurredAt: new Date(),\n data: {\n stepId: outcomeMarker.stepId,\n outcome: outcomeMarker.outcome,\n toStepId: dispatched.toStepId,\n transitionId: dispatched.transitionId,\n },\n })\n continue\n }\n if (dispatched.kind === 'failed') {\n errors.push(dispatched.error)\n events.push({\n eventType: 'OUTCOME_UNHANDLED',\n occurredAt: new Date(),\n data: { stepId: outcomeMarker.stepId, outcome: outcomeMarker.outcome },\n })\n await completeWorkflow(trx, container, instanceId, 'FAILED', { error: dispatched.error })\n return {\n status: 'FAILED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n }\n if (dispatched.kind === 'parked') {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n }\n\n const transitions = excludeNonNormalTransitions(definition.definition.transitions).filter(\n (t: any) =>\n t.fromStepId === currentInstance.currentStepId &&\n t.trigger === 'auto'\n )\n\n if (transitions.length === 0) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const transitionHandler = await import('./transition-handler')\n const evalContext: any = {\n workflowContext: currentInstance.context,\n userId: executionUserId,\n }\n\n const validTransitions = await transitionHandler.findValidTransitions(\n trx,\n currentInstance,\n currentInstance.currentStepId!,\n evalContext\n )\n\n const validAutoTransitions = validTransitions.filter(\n (vt) => vt.isValid && vt.transition?.trigger === 'auto'\n )\n\n if (validAutoTransitions.length === 0) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const selectedTransition = validAutoTransitions[0].transition\n\n try {\n const transitionResult = await transitionHandler.executeTransition(\n trx,\n container,\n currentInstance,\n selectedTransition.fromStepId,\n selectedTransition.toStepId,\n { ...evalContext, transitionId: selectedTransition.transitionId },\n )\n\n if (!transitionResult.success) {\n const rejectionMessage = transitionResult.error || 'Transition failed'\n\n // Error routing (spec 5.9): a wired error route is followed instead\n // of failing the instance; a failure-queue directive parks it. Both\n // are absent unless the definition opts in, so the legacy failure\n // path below is byte-identical for every existing definition.\n if (transitionResult.errorRoute && transitionResult.failedStepId) {\n const routed = await followErrorRoute(\n trx,\n container,\n currentInstance,\n transitionResult.failedStepId,\n transitionResult.errorRoute,\n rejectionMessage,\n evalContext\n )\n if (routed) {\n events.push({\n eventType: 'ERROR_ROUTED',\n occurredAt: new Date(),\n data: {\n failedStepId: transitionResult.failedStepId,\n toStepId: transitionResult.errorRoute.toStepId,\n transitionId: transitionResult.errorRoute.transitionId,\n },\n })\n continue\n }\n errors.push(`Error route from ${transitionResult.failedStepId} could not be followed`)\n }\n\n if (transitionResult.errorHandlerStepId && transitionResult.failedStepId) {\n const entered = await enterErrorHandlerStep(\n trx,\n container,\n currentInstance,\n transitionResult.failedStepId,\n transitionResult.errorHandlerStepId,\n rejectionMessage,\n executionUserId\n )\n if (entered) {\n events.push({\n eventType: 'ERROR_HANDLER_STARTED',\n occurredAt: new Date(),\n data: {\n failedStepId: transitionResult.failedStepId,\n handlerStepId: transitionResult.errorHandlerStepId,\n },\n })\n continue\n }\n errors.push(\n `Error handler step ${transitionResult.errorHandlerStepId} could not be entered`\n )\n }\n\n if (transitionResult.parkForAttention && transitionResult.failedStepId) {\n await parkInstanceForAttention(\n trx,\n currentInstance,\n transitionResult.failedStepId,\n rejectionMessage\n )\n events.push({\n eventType: 'ERROR_PARKED',\n occurredAt: new Date(),\n data: { failedStepId: transitionResult.failedStepId },\n })\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n logger.error('Transition rejected', {\n instanceId: currentInstance.id,\n workflowId: currentInstance.workflowId,\n fromStepId: currentInstance.currentStepId,\n toStepId: selectedTransition.toStepId,\n err: rejectionMessage,\n })\n errors.push(rejectionMessage)\n\n await completeWorkflow(trx, container, instanceId, 'FAILED', {\n error: rejectionMessage,\n })\n events.push({\n eventType: 'WORKFLOW_FAILED',\n occurredAt: new Date(),\n })\n\n return {\n status: 'FAILED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n }\n\n events.push({\n eventType: 'TRANSITION_EXECUTED',\n occurredAt: new Date(),\n data: {\n fromStepId: selectedTransition.fromStepId,\n toStepId: selectedTransition.toStepId,\n transitionId: selectedTransition.transitionId,\n },\n })\n\n // Spec 2026-06-26: step/stage advances re-emit `started` with the\n // destination stepId so projections can track stage transitions.\n await emitInstanceLifecycleEvent(currentInstance, 'workflows.instance.started', {\n stepId: selectedTransition.toStepId,\n fromStepId: selectedTransition.fromStepId,\n })\n\n if (transitionResult.pausedForActivities) {\n await logWorkflowEvent(trx, {\n workflowInstanceId: currentInstance.id,\n eventType: 'WORKFLOW_WAITING_FOR_ACTIVITIES',\n eventData: {\n pendingActivities: transitionResult.activitiesExecuted?.filter(a => a.async),\n pausedAtTransition: {\n fromStepId: selectedTransition.fromStepId,\n toStepId: selectedTransition.toStepId,\n },\n },\n tenantId: currentInstance.tenantId,\n organizationId: currentInstance.organizationId,\n })\n\n events.push({\n eventType: 'WORKFLOW_WAITING_FOR_ACTIVITIES',\n occurredAt: new Date(),\n data: {\n pendingActivities: transitionResult.activitiesExecuted?.filter(a => a.async),\n },\n })\n\n return {\n status: 'WAITING_FOR_ACTIVITIES',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n // The transition succeeded but the destination step parked the\n // instance (e.g. an INVOKE_AGENT AUTOMATED step enqueued an async\n // agent job and set PAUSED). The token cursor has already advanced to\n // that parked step, so currentInstance.currentStepId is the parked\n // step. Stop advancing until an external signal resumes it.\n if (transitionResult.paused) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n await trx.flush()\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n logger.error('Transition execution failed', {\n instanceId: currentInstance.id,\n workflowId: currentInstance.workflowId,\n fromStepId: currentInstance.currentStepId,\n toStepId: selectedTransition.toStepId,\n err: error,\n })\n errors.push(errorMessage)\n\n events.push({\n eventType: 'TRANSITION_FAILED',\n occurredAt: new Date(),\n data: {\n transitionId: selectedTransition.transitionId,\n error: errorMessage,\n },\n })\n\n await completeWorkflow(trx, container, instanceId, 'FAILED', {\n error: errorMessage,\n details: error instanceof WorkflowExecutionError ? error.details : undefined,\n })\n events.push({\n eventType: 'WORKFLOW_FAILED',\n occurredAt: new Date(),\n })\n\n return {\n status: 'FAILED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n }\n }\n\n errors.push('Maximum execution iterations reached - possible infinite loop')\n return {\n status: 'RUNNING',\n currentStep: instance.currentStepId,\n context: instance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n logger.error('Execution failed', { instanceId, err: error })\n errors.push(errorMessage)\n\n try {\n const instance = await getWorkflowInstanceForExecution(trx, instanceId, { refresh: true })\n if (instance && instance.status === 'RUNNING') {\n instance.status = 'FAILED'\n instance.errorMessage = errorMessage\n instance.errorDetails = error instanceof WorkflowExecutionError ? error.details : undefined\n instance.updatedAt = new Date()\n await writeRunOutcome(trx, instance, 'FAILED')\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_FAILED',\n eventData: { error: errorMessage },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n }\n } catch (updateError) {\n logger.error('Failed to update instance with error state', { instanceId, err: updateError })\n }\n\n throw error\n }\n }\n\n if (typeof transactionalEm.transactional !== 'function') {\n return runExecution(em)\n }\n\n try {\n return await transactionalEm.transactional((trx) => runExecution(trx))\n } catch (error) {\n // The throw has rolled back the execution transaction, discarding the\n // in-transaction FAILED write (and every step/bookkeeping advance) \u2014 which\n // would otherwise leave the instance silently stuck at RUNNING/start (#3632).\n // The in-transaction FAILED write is also futile when the underlying error\n // aborted the Postgres transaction (e.g. an effector issuing bad SQL): every\n // subsequent write on that connection fails. Now that the transaction \u2014 and\n // its PESSIMISTIC_WRITE lock on the instance row \u2014 has been released, durably\n // persist FAILED on an independent fork so the failure is visible and\n // retryable. Restores the #2593 \"persist FAILED\" guarantee even when the\n // whole transaction is discarded. Best-effort: never masks the original error.\n await persistFailedStatusAfterRollback(em, instanceId, error)\n throw error\n }\n}\n\nexport type AgentOutcomeDispatch =\n | { kind: 'routed'; toStepId: string; transitionId?: string; paused?: boolean }\n | { kind: 'parked' }\n | { kind: 'failed'; error: string }\n | { kind: 'default' }\n\n/**\n * Dispatch a resolved agent disposition for whatever step the instance is\n * currently on, or return null when there is no marker to act on.\n *\n * Exported because `sendSignal` advances a resumed instance ITSELF \u2014 it picks\n * the next transition and executes it before handing back to the executor \u2014 so\n * an outcome route wired on a parked agent step has to be honoured there too.\n * Routing it in only one of the two places is how a disposition silently takes\n * the happy path on the human-dispose path while working on the inline one.\n */\nexport async function dispatchAgentOutcomeForCurrentStep(\n em: EntityManager,\n container: AwilixContainer,\n instance: WorkflowInstance,\n definition: OutcomeRoutingDefinitionLike,\n evalContext: { workflowContext: Record<string, unknown>; userId?: string }\n): Promise<AgentOutcomeDispatch | null> {\n const marker = readAgentOutcomeMarker(instance.context, instance.currentStepId ?? '')\n if (!marker) return null\n return await dispatchAgentOutcome(em, container, instance, definition, marker, evalContext)\n}\n\n/**\n * Act on a resolved agent disposition (spec 7.2).\n *\n * The engine-owned marker is consumed here \u2014 cleared before anything else runs \u2014\n * so a route that loops back through the same step cannot re-fire on the old\n * disposition, and so a `default` outcome leaves no residue in the run context.\n *\n * `default` means \"route exactly as this instance always would have\": the step\n * wired no outcome at all, or the outcome is `approved`, which \u00A77.2 renders as\n * the node's ordinary output. Only a step that opted into outcome routing can\n * reach the inheritance branch, which is what keeps this additive.\n */\nasync function dispatchAgentOutcome(\n em: EntityManager,\n container: AwilixContainer,\n instance: WorkflowInstance,\n definition: OutcomeRoutingDefinitionLike,\n marker: WorkflowAgentOutcomeContextEntry,\n evalContext: { workflowContext: Record<string, unknown>; userId?: string }\n): Promise<AgentOutcomeDispatch> {\n const { [WORKFLOW_AGENT_OUTCOME_CONTEXT_KEY]: _consumed, ...remainingContext } =\n (instance.context || {}) as Record<string, unknown>\n instance.context = remainingContext\n instance.updatedAt = new Date()\n await em.flush()\n\n const clearedEvalContext = {\n ...evalContext,\n workflowContext: remainingContext,\n }\n\n const failUnhandled = async (error: string): Promise<AgentOutcomeDispatch> => {\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'OUTCOME_UNHANDLED',\n eventData: { stepId: marker.stepId, outcome: marker.outcome, error },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n return { kind: 'failed', error }\n }\n\n const handling = resolveAgentOutcomeHandling(definition, marker.stepId, marker.outcome)\n if (handling.kind === 'default') return { kind: 'default' }\n\n if (handling.kind === 'route') {\n const toStepId = handling.transition.toStepId\n if (!toStepId) return { kind: 'default' }\n\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'OUTCOME_ROUTED',\n eventData: {\n stepId: marker.stepId,\n outcome: marker.outcome,\n toStepId,\n transitionId: handling.transition.transitionId,\n proposalId: marker.proposalId,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n const transitionHandler = await import('./transition-handler')\n const routed = await transitionHandler.executeTransition(\n em,\n container,\n instance,\n marker.stepId,\n toStepId,\n { ...clearedEvalContext, transitionId: handling.transition.transitionId },\n )\n if (routed.success) {\n return {\n kind: 'routed',\n toStepId,\n transitionId: handling.transition.transitionId,\n paused: routed.paused,\n }\n }\n return await failUnhandled(`Outcome route for \"${marker.outcome}\" could not be followed`)\n }\n\n // `inherit`: an unwired non-approved outcome follows the complete step-error\n // handling contract, including continuation, failure-queue parking and the\n // definition-level handler step.\n const unhandled = `Agent step ${marker.stepId} resolved outcome \"${marker.outcome}\", which is not wired`\n if (handling.handling.kind === 'route') {\n const errorRoute = handling.handling.transition\n if (errorRoute.toStepId) {\n const routed = await followErrorRoute(\n em,\n container,\n instance,\n marker.stepId,\n { transitionId: errorRoute.transitionId, toStepId: errorRoute.toStepId },\n unhandled,\n clearedEvalContext\n )\n if (routed) {\n return {\n kind: 'routed',\n toStepId: errorRoute.toStepId,\n transitionId: errorRoute.transitionId,\n paused: instance.status === 'PAUSED',\n }\n }\n }\n }\n\n if (handling.handling.kind === 'continue') {\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'ERROR_DIRECTIVE_APPLIED',\n eventData: {\n stepId: marker.stepId,\n directive: 'continueWithFallback',\n source: 'agentOutcome',\n hasFallbackValue: handling.handling.fallbackValue !== undefined,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n if (handling.handling.fallbackValue !== undefined) {\n instance.context = {\n ...(instance.context || {}),\n [marker.stepId]: handling.handling.fallbackValue,\n }\n instance.updatedAt = new Date()\n await em.flush()\n }\n return { kind: 'default' }\n }\n\n if (handling.handling.kind === 'park') {\n await parkInstanceForAttention(em, instance, marker.stepId, unhandled)\n return { kind: 'parked' }\n }\n\n if (handling.handling.kind === 'handlerStep') {\n const entered = await enterErrorHandlerStep(\n em,\n container,\n instance,\n marker.stepId,\n handling.handling.stepId,\n unhandled,\n clearedEvalContext.userId,\n )\n if (entered) {\n return {\n kind: 'routed',\n toStepId: handling.handling.stepId,\n paused: instance.status === 'PAUSED',\n }\n }\n }\n\n return await failUnhandled(unhandled)\n}\n\n/**\n * Follow a wired error route out of a failed step (spec 5.9). The failure is\n * published into the run context under `__error` so the handling branch can act\n * on it, then the error transition executes through the normal machinery \u2014 it\n * creates its step instance, runs its activities and logs its events like any\n * other route. Returns false when the route could not be taken, so the caller\n * falls back to the untouched failure path.\n */\nasync function followErrorRoute(\n em: EntityManager,\n container: AwilixContainer,\n instance: WorkflowInstance,\n failedStepId: string,\n errorRoute: { transitionId?: string; toStepId: string },\n error: string,\n evalContext: { workflowContext: Record<string, any>; userId?: string }\n): Promise<boolean> {\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'ERROR_ROUTED',\n eventData: {\n failedStepId,\n toStepId: errorRoute.toStepId,\n transitionId: errorRoute.transitionId,\n error,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n const errorEntry = buildErrorContextEntry(failedStepId, error)\n instance.context = {\n ...(instance.context || {}),\n [WORKFLOW_ERROR_CONTEXT_KEY]: errorEntry,\n }\n instance.updatedAt = new Date()\n await em.flush()\n\n const transitionHandler = await import('./transition-handler')\n const routedResult = await transitionHandler.executeTransition(\n em,\n container,\n instance,\n failedStepId,\n errorRoute.toStepId,\n {\n ...evalContext,\n workflowContext: {\n ...evalContext.workflowContext,\n [WORKFLOW_ERROR_CONTEXT_KEY]: errorEntry,\n },\n transitionId: errorRoute.transitionId,\n },\n )\n\n return routedResult.success === true\n}\n\n/**\n * Enter the definition-level handler STEP (spec 5.9, `errorHandler.stepId`) for\n * a failure no route and no directive handled. The token jumps to the handler\n * step and executes it \u2014 the same cursor-move-plus-`executeStep` shape the\n * branch/timer/signal resumes already use, so no transition record is invented.\n * A failure of the handler step itself resolves to `fail` (the resolver never\n * jumps a step to itself), which is this form's recursion guard.\n */\nasync function enterErrorHandlerStep(\n em: EntityManager,\n container: AwilixContainer,\n instance: WorkflowInstance,\n failedStepId: string,\n handlerStepId: string,\n error: string,\n userId?: string\n): Promise<boolean> {\n const errorEntry = buildErrorContextEntry(failedStepId, error)\n\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'ERROR_HANDLER_STARTED',\n eventData: { failedStepId, handlerStepId, error },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n instance.context = {\n ...(instance.context || {}),\n [WORKFLOW_ERROR_CONTEXT_KEY]: errorEntry,\n }\n instance.currentStepId = handlerStepId\n instance.updatedAt = new Date()\n await em.flush()\n\n const { executeStep } = await import('./step-handler')\n const result = await executeStep(\n em,\n instance,\n handlerStepId,\n {\n workflowContext: {\n ...(instance.context || {}),\n [WORKFLOW_ERROR_CONTEXT_KEY]: errorEntry,\n },\n userId,\n },\n container\n )\n\n return result.status !== 'FAILED'\n}\n\n/**\n * Park a step-through run before the step the author has not released yet.\n *\n * Reuses PAUSED exactly as the failure queue does, and deliberately writes NO\n * `attention` marker: the run is waiting for the author, not for triage, so it\n * must not appear in the failure queue.\n */\nasync function pauseForStepThrough(\n em: EntityManager,\n instance: WorkflowInstance\n): Promise<void> {\n const now = new Date()\n instance.status = 'PAUSED'\n instance.pausedAt = now\n instance.updatedAt = now\n await em.flush()\n\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: STEP_THROUGH_EVENT_TYPE,\n eventData: { stepId: instance.currentStepId },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n}\n\n/**\n * Park an instance for triage instead of failing it \u2014 the `failureQueue` error\n * directive (spec 5.9 \"Send to failure queue\"). Uses the existing PAUSED state\n * plus an engine-owned `metadata.attention` marker; no new instance status and\n * no compensation, because the run is suspended rather than terminated.\n */\nasync function parkInstanceForAttention(\n em: EntityManager,\n instance: WorkflowInstance,\n failedStepId: string,\n error: string\n): Promise<void> {\n const now = new Date()\n instance.status = 'PAUSED'\n instance.pausedAt = now\n instance.errorMessage = error\n instance.metadata = {\n ...(instance.metadata || {}),\n attention: {\n reason: 'ERROR_DIRECTIVE',\n stepId: failedStepId,\n error,\n at: now.toISOString(),\n },\n }\n instance.updatedAt = now\n await em.flush()\n\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'ERROR_PARKED',\n eventData: { failedStepId, error, directive: 'failureQueue' },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n}\n\n/**\n * Durably mark a workflow instance FAILED after its execution transaction has\n * rolled back. MUST run on a fresh fork (a clean connection): the rolled-back\n * transaction may be aborted/poisoned, and its PESSIMISTIC_WRITE lock on the\n * instance row is released only once the transactional callback unwinds, so an\n * in-transaction write here would be discarded or deadlock. Only transitions a\n * still-`RUNNING` instance (leaves CANCELLED/COMPLETED/PAUSED untouched).\n */\nasync function persistFailedStatusAfterRollback(\n em: EntityManager,\n instanceId: string,\n error: unknown,\n): Promise<void> {\n const errorMessage = error instanceof Error ? error.message : String(error)\n const errorDetails = error instanceof WorkflowExecutionError ? error.details : undefined\n const markFailed = async (trx: EntityManager): Promise<void> => {\n const instance = await trx.findOne(\n WorkflowInstance,\n { id: instanceId },\n { lockMode: LockMode.PESSIMISTIC_WRITE },\n )\n if (!instance || instance.status !== 'RUNNING') return\n instance.status = 'FAILED'\n instance.errorMessage = errorMessage\n instance.errorDetails = errorDetails\n instance.updatedAt = new Date()\n await writeRunOutcome(trx, instance, 'FAILED')\n await trx.flush()\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_FAILED',\n eventData: { error: errorMessage },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n await emitInstanceLifecycleEvent(instance, 'workflows.instance.failed')\n }\n try {\n if (typeof (em as { fork?: unknown }).fork !== 'function') return\n const fork = em.fork() as EntityManager & {\n transactional?: <TResult>(callback: (trx: EntityManager) => Promise<TResult>) => Promise<TResult>\n }\n if (typeof fork.transactional === 'function') {\n await fork.transactional((trx) => markFailed(trx))\n } else {\n await markFailed(fork)\n }\n } catch (persistError) {\n logger.error('failed to durably persist FAILED status after rollback', {\n instanceId,\n error: persistError instanceof Error ? persistError.message : String(persistError),\n })\n }\n}\n\n/**\n * Write the run's terminal VERDICT onto the instance, and guarantee it has a\n * terminal timestamp.\n *\n * The ONE write site, so `outcome` cannot be assembled ad hoc per exit point:\n * every caller hands over the terminal status and the pure\n * `resolveRunOutcome` decides from the evidence the run recorded. Called before\n * the flush that persists the terminal status, so status and verdict land in the\n * same UPDATE and no reader can observe one without the other.\n *\n * The timestamp backstop closes a real gap. `compensation-handler` flips the\n * status to COMPENSATED (or back to FAILED on a partial compensation) and\n * `completeWorkflow` RETURNS before its own `completedAt` assignment on that\n * path, so a compensated run had no terminal instant at all \u2014 it could be\n * attributed to no KPI window and its duration was unmeasurable. Every other\n * path already assigns one, so this only ever fills a hole; it never moves an\n * instant that was already recorded, and CANCELLED is excluded because\n * `cancelledAt` is its terminal instant.\n */\nasync function writeRunOutcome(\n em: EntityManager,\n instance: WorkflowInstance,\n terminalStatus: string,\n): Promise<void> {\n const evidence = await collectRunOutcomeEvidence(em, instance, terminalStatus)\n instance.outcome = resolveRunOutcome(evidence)\n\n if (terminalStatus !== 'CANCELLED' && !instance.completedAt) {\n instance.completedAt = new Date()\n }\n}\n\n/**\n * Complete a workflow instance with final status\n *\n * @param em - Entity manager\n * @param container\n * @param instanceId - Workflow instance ID\n * @param status - Final status (COMPLETED, FAILED, CANCELLED)\n * @param result - Optional result data\n */\nexport async function completeWorkflow(\n em: EntityManager,\n container: AwilixContainer,\n instanceId: string,\n status: 'COMPLETED' | 'FAILED' | 'CANCELLED',\n result?: any\n): Promise<void> {\n const instance = await getWorkflowInstance(em, instanceId)\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n // Workflow-level error handler (spec 5.9) \u2014 scheduled BEFORE compensation so\n // the handler observes the state that failed rather than the rolled-back one,\n // and so it still runs when compensation throws (that block swallows errors\n // and returns early). Executed out of band by the worker; the\n // ERROR_HANDLER_SCHEDULED event is written here, inside this transaction.\n if (status === 'FAILED') {\n await scheduleWorkflowErrorHandler(em, instance, {\n failedStepId: result?.failedStepId ?? instance.currentStepId,\n error: result?.error,\n details: result?.details,\n })\n }\n\n // Trigger compensation if workflow failed and has compensatable activities (Phase 8.2)\n if (status === 'FAILED') {\n const definition = await findDefinitionForInstance(em, instance)\n\n if (definition && checkIfCompensationNeeded(definition)) {\n try {\n\n // Set error message before compensation\n if (result?.error) {\n instance.errorMessage = result.error\n instance.errorDetails = result.details\n await em.flush()\n }\n\n const compensationResult = await compensateWorkflow(\n em,\n container,\n instance,\n definition,\n {\n continueOnError: true // Best-effort compensation\n }\n )\n\n logger.info('Compensation finished', {\n status: compensationResult.status,\n compensatedActivities: compensationResult.compensatedActivities,\n totalActivities: compensationResult.totalActivities,\n })\n\n // Note: instance status already updated by compensateWorkflow\n // It will be COMPENSATED or remain FAILED. This branch RETURNS, so the\n // verdict is written here rather than at the shared tail below \u2014 same\n // resolver, same evidence, one more call site than the ideal one.\n await writeRunOutcome(em, instance, instance.status)\n await em.flush()\n\n // A compensated/failed child must still resume its parent SUB_WORKFLOW\n // step \u2014 otherwise a parent parked on this child stays PAUSED forever.\n // From the parent's perspective the sub-workflow did not succeed, so this\n // mirrors the normal-path enqueue below but always signals FAILED.\n await enqueueSubWorkflowParentResume(instance, 'FAILED')\n // Terminal signal for external projections: the run did not succeed,\n // regardless of whether compensation left it COMPENSATED or FAILED\n // (payload `status` carries the actual post-compensation status).\n await emitInstanceLifecycleEvent(instance, 'workflows.instance.failed')\n return\n } catch (error: any) {\n logger.error('Compensation failed with exception', { err: error })\n // Continue to mark workflow as failed\n }\n }\n }\n\n // Original completion logic (no compensation needed or status is COMPLETED/CANCELLED)\n const now = new Date()\n instance.status = status\n instance.updatedAt = now\n\n switch (status) {\n case 'COMPLETED':\n instance.completedAt = now\n if (result) {\n instance.context = { ...instance.context, __result: result }\n }\n break\n\n case 'FAILED':\n instance.completedAt = now\n if (result?.error) {\n instance.errorMessage = result.error\n instance.errorDetails = result.details\n }\n break\n\n case 'CANCELLED':\n instance.cancelledAt = now\n break\n }\n\n await writeRunOutcome(em, instance, status)\n\n await em.flush()\n\n // Log completion event\n const eventType =\n status === 'COMPLETED'\n ? 'WORKFLOW_COMPLETED'\n : status === 'FAILED'\n ? 'WORKFLOW_FAILED'\n : 'WORKFLOW_CANCELLED'\n\n await logWorkflowEvent(em, {\n workflowInstanceId: instanceId,\n eventType,\n eventData: result || {},\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n await emitInstanceLifecycleEvent(\n instance,\n status === 'COMPLETED'\n ? 'workflows.instance.completed'\n : status === 'FAILED'\n ? 'workflows.instance.failed'\n : 'workflows.instance.cancelled'\n )\n\n // If this instance is a child of a parked SUB_WORKFLOW step, enqueue a job to\n // resume the parent on the worker's own connection (never inline inside the\n // child's transaction \u2014 lock-ordering hazard). The worker guard skips the job\n // when the parent never parked (fully-synchronous fast path).\n if (status === 'COMPLETED' || status === 'FAILED') {\n await enqueueSubWorkflowParentResume(instance, status)\n }\n}\n\n/**\n * Enqueue a `resume_subworkflow_parent` job when a terminating instance carries a\n * parent linkage. Best-effort: a queue hiccup must not undo the just-persisted\n * terminal status, so failures are logged rather than thrown. The small delay\n * lets the parent's PAUSED flush become visible before the worker runs.\n */\nasync function enqueueSubWorkflowParentResume(\n instance: WorkflowInstance,\n childStatus: 'COMPLETED' | 'FAILED'\n): Promise<void> {\n const labels = instance.metadata?.labels\n const parentInstanceId = labels?.parentInstanceId\n const parentStepId = labels?.parentStepId\n const parentStepInstanceId = labels?.parentStepInstanceId\n if (!parentInstanceId || !parentStepId || !parentStepInstanceId) return\n\n try {\n const { createModuleQueue } = await import('@open-mercato/queue')\n const { WORKFLOW_ACTIVITIES_QUEUE_NAME } = await import('./activity-queue-types')\n const { INVOKE_AGENT_ENQUEUE_DELAY_MS } = await import('./activity-executor')\n\n const queue = createModuleQueue<WorkflowActivityJob>(WORKFLOW_ACTIVITIES_QUEUE_NAME, {\n concurrency: parseInt(process.env.WORKFLOW_WORKER_CONCURRENCY || '5'),\n })\n\n const job: WorkflowActivityJobResumeSubWorkflowParent = {\n kind: 'resume_subworkflow_parent',\n workflowInstanceId: parentInstanceId,\n parentInstanceId,\n parentStepId,\n parentStepInstanceId,\n childInstanceId: instance.id,\n childStatus,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n }\n await queue.enqueue(job, { delayMs: INVOKE_AGENT_ENQUEUE_DELAY_MS })\n } catch (error) {\n logger.error('failed to enqueue parent-resume job', {\n childInstanceId: instance.id,\n parentInstanceId,\n error: error instanceof Error ? error.message : String(error),\n })\n }\n}\n\n/**\n * Resume workflow after async activities complete\n *\n * Called by the activity worker after all async activities finish execution.\n * Checks if all activities are done, merges outputs into context, and resumes execution.\n *\n * @param em - Entity manager\n * @param container - DI container\n * @param instanceId - Workflow instance ID\n */\nexport async function resumeWorkflowAfterActivities(\n em: EntityManager,\n container: AwilixContainer,\n instanceId: string,\n branchInstanceId?: string | null\n): Promise<void> {\n const transactionalEm = em as EntityManager & {\n transactional?: <TResult>(callback: (trx: EntityManager) => Promise<TResult>) => Promise<TResult>\n }\n\n // Branch-scoped async resume: the instance is FORKED and the branch (not the\n // instance) is WAITING_FOR_ACTIVITIES. Resume just that branch, then let the\n // interleaved loop continue. Missing branchInstanceId \u2192 legacy instance path.\n if (branchInstanceId) {\n const { resumeBranchAfterActivities } = await import('./parallel-handler')\n const branchResume = typeof transactionalEm.transactional === 'function'\n ? await transactionalEm.transactional((trx) => resumeBranchAfterActivities(trx, container, instanceId, branchInstanceId))\n : await resumeBranchAfterActivities(em, container, instanceId, branchInstanceId)\n if (branchResume.continueExecution) {\n await executeWorkflow(em, container, instanceId)\n }\n return\n }\n\n const runResume = async (trx: EntityManager): Promise<{ continueExecution: boolean }> => {\n const instance = await trx.findOne(WorkflowInstance, {\n id: instanceId,\n status: 'WAITING_FOR_ACTIVITIES',\n }, { lockMode: LockMode.PESSIMISTIC_WRITE })\n\n if (!instance) {\n throw new Error('Workflow instance not waiting for activities')\n }\n\n const pendingJobIds = readPendingAsyncJobIds(instance.context._pendingAsyncActivities)\n\n const outcomeEvents = pendingJobIds.length === 0\n ? []\n : await trx.find(\n WorkflowEvent,\n {\n workflowInstanceId: instanceId,\n eventType: { $in: [...ASYNC_ACTIVITY_OUTCOME_EVENT_TYPES] },\n eventData: { async: true, jobId: { $in: pendingJobIds } },\n },\n { orderBy: { occurredAt: 'asc', id: 'asc' } },\n )\n const wait = resolveAsyncActivityWait(pendingJobIds, outcomeEvents)\n\n if (!wait.settled) {\n throw new Error('Activities still pending')\n }\n\n const completedEvents = wait.completed\n const failedEvents = wait.failed\n const completedActivities = completedEvents.length\n const failedActivities = failedEvents.length\n\n if (failedActivities > 0) {\n instance.status = 'FAILED'\n instance.errorMessage = `${failedActivities} async activities failed`\n instance.errorDetails = {\n failedActivities: failedEvents.map(e => ({\n activityId: e.eventData.activityId,\n error: e.eventData.error,\n jobId: e.eventData.jobId,\n })),\n }\n await writeRunOutcome(trx, instance, 'FAILED')\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_FAILED',\n eventData: {\n reason: 'Async activities failed',\n failedActivities: instance.errorDetails.failedActivities,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return { continueExecution: false }\n }\n\n for (const event of completedEvents) {\n if (event.eventData.output) {\n instance.context = {\n ...instance.context,\n [`${event.eventData.activityId}_result`]: event.eventData.output,\n }\n }\n }\n\n delete instance.context._pendingAsyncActivities\n\n const pendingTransition = instance.pendingTransition\n\n if (!pendingTransition) {\n logger.warn('No pending transition found during resume')\n instance.status = 'RUNNING'\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_RESUMED',\n eventData: {\n reason: 'All async activities completed',\n completedActivities: completedActivities,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return { continueExecution: true }\n }\n\n logger.debug('Completing pending transition', {\n toStepId: pendingTransition.toStepId,\n fromStepId: instance.currentStepId,\n })\n\n const definition = await findDefinitionForInstance(trx, instance)\n if (!definition) {\n throw new WorkflowExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n const step = definition.definition.steps.find(s => s.stepId === pendingTransition.toStepId)\n\n instance.currentStepId = pendingTransition.toStepId\n instance.status = 'RUNNING'\n instance.pendingTransition = null\n instance.updatedAt = new Date()\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instance.id,\n eventType: 'STEP_ENTERED',\n eventData: {\n stepId: pendingTransition.toStepId,\n stepName: step?.stepName,\n stepType: step?.stepType,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_RESUMED',\n eventData: {\n reason: 'Async activities completed, resuming pending transition',\n completedActivities: completedActivities,\n completedTransitionTo: pendingTransition.toStepId,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // The async-resume path runs inside a worker, so it re-resolves the actor\n // from the definition exactly as the main loop does \u2014 otherwise a granted\n // workflow would revert to the starting user's identity the moment one of\n // its activities went async.\n const resumeDefinition = await findDefinitionForInstance(trx, instance)\n const { executeStep } = await import('./step-handler')\n await executeStep(\n trx,\n instance,\n pendingTransition.toStepId,\n {\n workflowContext: instance.context || {},\n userId: resumeDefinition\n ? await resolveRunActorUserId(trx, resumeDefinition, undefined, instance)\n : resolveWorkflowExecutionUserId(undefined, instance),\n },\n container\n )\n\n return { continueExecution: true }\n }\n\n const resumeResult = typeof transactionalEm.transactional === 'function'\n ? await transactionalEm.transactional((trx) => runResume(trx))\n : await runResume(em)\n\n if (resumeResult.continueExecution) {\n await executeWorkflow(em, container, instanceId)\n }\n}\n\n/**\n * Check if workflow definition has any compensatable activities\n */\nfunction checkIfCompensationNeeded(definition: WorkflowDefinition): boolean {\n // Check if any activities have compensation defined\n for (const transition of definition.definition.transitions) {\n if (transition.activities) {\n for (const activity of transition.activities) {\n if (activity.compensation?.activityId) {\n return true\n }\n }\n }\n }\n\n // Check root-level activities (legacy)\n if (definition.definition.activities) {\n for (const activity of definition.definition.activities) {\n if (activity.compensation?.activityId) {\n return true\n }\n }\n }\n\n return false\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Get workflow instance by ID.\n *\n * SECURITY: this helper is NOT tenant-scoped. It is an internal lookup whose\n * callers are expected to have resolved and enforced the scope already. Never\n * reach it directly from an HTTP handler \u2014 use a scoped query (see\n * `updateWorkflowContextScoped`) so a cross-tenant id cannot resolve.\n *\n * @param em - Entity manager\n * @param instanceId - Workflow instance ID\n * @returns Workflow instance or null if not found\n */\nexport async function getWorkflowInstance(\n em: EntityManager,\n instanceId: string\n): Promise<WorkflowInstance | null> {\n return em.findOne(WorkflowInstance, { id: instanceId })\n}\n\nasync function getWorkflowInstanceForExecution(\n em: EntityManager,\n instanceId: string,\n options?: { refresh?: boolean }\n): Promise<WorkflowInstance | null> {\n return em.findOne(\n WorkflowInstance,\n { id: instanceId },\n {\n lockMode: LockMode.PESSIMISTIC_WRITE,\n ...(options?.refresh ? { refresh: true } : {}),\n }\n )\n}\n\n/**\n * Update workflow context with new data.\n *\n * SECURITY: builds on the UNSCOPED {@link getWorkflowInstance} and therefore\n * performs no tenant/organization filtering of its own. It is preserved as-is\n * for backward compatibility (it is a DI-exposed surface). HTTP handlers MUST\n * use {@link updateWorkflowContextScoped} instead.\n *\n * @param em - Entity manager\n * @param instanceId - Workflow instance ID\n * @param updates - Context updates (merged with existing context)\n */\nexport async function updateWorkflowContext(\n em: EntityManager,\n instanceId: string,\n updates: Record<string, any>\n): Promise<void> {\n const instance = await getWorkflowInstance(em, instanceId)\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n instance.context = {\n ...instance.context,\n ...updates,\n }\n instance.updatedAt = new Date()\n\n await em.flush()\n}\n\n/**\n * Context keys the engine owns. A caller-supplied patch may never write them:\n * `__result` carries the terminal workflow result, `_pendingAsyncActivities`\n * tracks in-flight async activity jobs, and `__park` marks a parked agent step.\n * Overwriting any of them would corrupt a running instance, so they are\n * rejected rather than silently dropped.\n */\nexport const RESERVED_WORKFLOW_CONTEXT_KEYS: readonly string[] = [\n '__result',\n '_pendingAsyncActivities',\n '__park',\n WORKFLOW_ERROR_CONTEXT_KEY,\n]\n\nexport function findReservedContextKeys(updates: Record<string, unknown>): string[] {\n return Object.keys(updates).filter((key) => RESERVED_WORKFLOW_CONTEXT_KEYS.includes(key))\n}\n\nexport interface UpdateWorkflowContextScopedOptions {\n instanceId: string\n tenantId: string\n organizationId: string\n updates: Record<string, unknown>\n /**\n * Optional version check, awaited with the freshly loaded row's `updatedAt`\n * before the patch is applied. HTTP callers pass\n * `enforceCommandOptimisticLockWithGuards` here so a stale write 409s instead\n * of silently clobbering a concurrent context change.\n */\n assertVersion?: (current: Date | null | undefined) => void | Promise<void>\n}\n\n/**\n * Tenant/organization-scoped sibling of {@link updateWorkflowContext}: the\n * scope is part of the lookup, so a cross-tenant instance id resolves to\n * nothing and the caller returns a 404 rather than reading or writing another\n * tenant's run. Shallow merge, consistent with the legacy helper.\n */\nexport async function updateWorkflowContextScoped(\n em: EntityManager,\n options: UpdateWorkflowContextScopedOptions\n): Promise<WorkflowInstance> {\n const { instanceId, tenantId, organizationId, updates, assertVersion } = options\n\n const reserved = findReservedContextKeys(updates)\n if (reserved.length > 0) {\n throw new WorkflowExecutionError(\n `Reserved workflow context keys cannot be written: ${reserved.join(', ')}`,\n 'RESERVED_CONTEXT_KEY',\n { instanceId, reserved }\n )\n }\n\n const instance = await findOneWithDecryption(\n em as PostgreSqlEntityManager,\n WorkflowInstance,\n { id: instanceId, tenantId, organizationId },\n undefined,\n { tenantId, organizationId }\n )\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n if (instance.status !== 'RUNNING' && instance.status !== 'PAUSED' && instance.status !== 'FORKED') {\n throw new WorkflowExecutionError(\n `Workflow instance is not accepting context updates: ${instance.status}`,\n 'INSTANCE_NOT_UPDATABLE',\n { instanceId, status: instance.status }\n )\n }\n\n if (assertVersion) await assertVersion(instance.updatedAt)\n\n instance.context = {\n ...instance.context,\n ...updates,\n }\n instance.updatedAt = new Date()\n\n await em.flush()\n\n return instance\n}\n\n// findWorkflowDefinition is imported from ./find-definition\n\ntype InstanceLifecycleEventId =\n | 'workflows.instance.created'\n | 'workflows.instance.started'\n | 'workflows.instance.completed'\n | 'workflows.instance.failed'\n | 'workflows.instance.cancelled'\n\n/**\n * Publish a declared `workflows.instance.*` lifecycle event to the event bus,\n * alongside (never instead of) the internal `WorkflowEvent` audit row. Delivery\n * is at-least-once and consumers must be idempotent; a bus failure must never\n * break workflow execution, so this is strictly best-effort.\n */\nasync function emitInstanceLifecycleEvent(\n instance: WorkflowInstance,\n eventId: InstanceLifecycleEventId,\n extra?: Record<string, unknown>\n): Promise<void> {\n try {\n await emitWorkflowsEvent(\n eventId,\n {\n id: instance.id,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n workflowId: instance.workflowId,\n version: instance.version,\n status: instance.status,\n stepId: instance.currentStepId ?? null,\n ...extra,\n },\n { persistent: true }\n )\n } catch (error) {\n logger.error('failed to emit workflow event', {\n eventId,\n instanceId: instance.id,\n error: error instanceof Error ? error.message : String(error),\n })\n }\n}\n\n/**\n * Log workflow event to event sourcing table\n *\n * @param em - Entity manager\n * @param event - Event data\n */\nasync function logWorkflowEvent(\n em: EntityManager,\n event: {\n workflowInstanceId: string\n stepInstanceId?: string\n eventType: string\n eventData: any\n userId?: string\n tenantId: string\n organizationId: string\n }\n): Promise<WorkflowEvent> {\n const workflowEvent = em.create(WorkflowEvent, {\n ...event,\n occurredAt: new Date(),\n })\n\n await em.persist(workflowEvent).flush()\n return workflowEvent\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.9.1-develop.7519.1.38f51f8dbb",
3
+ "version": "0.9.1-develop.7532.1.8eac7e198f",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -264,16 +264,16 @@
264
264
  "zod": "^4.4.3"
265
265
  },
266
266
  "peerDependencies": {
267
- "@open-mercato/ai-assistant": "0.9.1-develop.7519.1.38f51f8dbb",
268
- "@open-mercato/shared": "0.9.1-develop.7519.1.38f51f8dbb",
269
- "@open-mercato/ui": "0.9.1-develop.7519.1.38f51f8dbb",
267
+ "@open-mercato/ai-assistant": "0.9.1-develop.7532.1.8eac7e198f",
268
+ "@open-mercato/shared": "0.9.1-develop.7532.1.8eac7e198f",
269
+ "@open-mercato/ui": "0.9.1-develop.7532.1.8eac7e198f",
270
270
  "react": "^19.0.0",
271
271
  "react-dom": "^19.0.0"
272
272
  },
273
273
  "devDependencies": {
274
- "@open-mercato/ai-assistant": "0.9.1-develop.7519.1.38f51f8dbb",
275
- "@open-mercato/shared": "0.9.1-develop.7519.1.38f51f8dbb",
276
- "@open-mercato/ui": "0.9.1-develop.7519.1.38f51f8dbb",
274
+ "@open-mercato/ai-assistant": "0.9.1-develop.7532.1.8eac7e198f",
275
+ "@open-mercato/shared": "0.9.1-develop.7532.1.8eac7e198f",
276
+ "@open-mercato/ui": "0.9.1-develop.7532.1.8eac7e198f",
277
277
  "@testing-library/dom": "^10.4.1",
278
278
  "@testing-library/jest-dom": "^7.0.1",
279
279
  "@testing-library/react": "^16.3.3",
@@ -22,7 +22,12 @@ const emptyAuthTokenClaims: AuthTokenClaims = Object.freeze({
22
22
  function parseCookie(req: Request, name: string): string | null {
23
23
  const cookie = req.headers.get('cookie') || ''
24
24
  const m = cookie.match(new RegExp('(?:^|;\\s*)' + name + '=([^;]+)'))
25
- return m ? decodeURIComponent(m[1]) : null
25
+ if (!m) return null
26
+ try {
27
+ return decodeURIComponent(m[1])
28
+ } catch {
29
+ return null
30
+ }
26
31
  }
27
32
 
28
33
  function readStringClaim(payload: Record<string, unknown>, key: string): string | null {
@@ -22,7 +22,12 @@ const refreshIpRateLimitConfig = readEndpointRateLimitConfig('REFRESH_IP', {
22
22
  function parseCookie(req: Request, name: string): string | null {
23
23
  const cookie = req.headers.get('cookie') || ''
24
24
  const m = cookie.match(new RegExp('(?:^|;\\s*)' + name + '=([^;]+)'))
25
- return m ? decodeURIComponent(m[1]) : null
25
+ if (!m) return null
26
+ try {
27
+ return decodeURIComponent(m[1])
28
+ } catch {
29
+ return null
30
+ }
26
31
  }
27
32
 
28
33
  // Both handlers are `requireAuth: false`, so the dispatcher's MFA-pending gate never inspects
@@ -659,6 +659,16 @@ function mediaLabel(row: Attachment): string {
659
659
  return row.id
660
660
  }
661
661
 
662
+ function mediaUpdatePatch(entry: {
663
+ altText?: string
664
+ caption?: string
665
+ }): { altText?: string; caption?: string } {
666
+ return {
667
+ ...(entry.altText !== undefined ? { altText: entry.altText } : {}),
668
+ ...(entry.caption !== undefined ? { caption: entry.caption } : {}),
669
+ }
670
+ }
671
+
662
672
  const updateProductMediaDescriptionsTool: CatalogAiToolDefinition = {
663
673
  name: 'catalog.update_product_media_descriptions',
664
674
  displayName: 'Update product media descriptions',
@@ -678,12 +688,14 @@ const updateProductMediaDescriptionsTool: CatalogAiToolDefinition = {
678
688
  for (const entry of input.mediaUpdates) {
679
689
  const media = await loadProductMediaForScope(em, ctx, tenantId, entry.mediaId)
680
690
  if (!media) continue
691
+ const before = mediaSnapshot(media)
681
692
  rows.push({
682
693
  recordId: media.id,
683
694
  entityType: 'catalog.product_media',
684
695
  label: mediaLabel(media),
685
696
  recordVersion: recordVersionFromUpdatedAt(media.createdAt ?? null),
686
- before: mediaSnapshot(media),
697
+ before,
698
+ after: { ...before, ...mediaUpdatePatch(entry) },
687
699
  })
688
700
  }
689
701
  return rows
@@ -712,10 +724,7 @@ const updateProductMediaDescriptionsTool: CatalogAiToolDefinition = {
712
724
  const before = mediaSnapshot(media)
713
725
  touched.push({
714
726
  row: media,
715
- patch: {
716
- ...(entry.altText !== undefined ? { altText: entry.altText } : {}),
717
- ...(entry.caption !== undefined ? { caption: entry.caption } : {}),
718
- },
727
+ patch: mediaUpdatePatch(entry),
719
728
  before,
720
729
  })
721
730
  }
@@ -46,6 +46,7 @@ export interface CatalogToolLoadBeforeRecord {
46
46
  label: string
47
47
  recordVersion: string | null
48
48
  before: Record<string, unknown>
49
+ after?: Record<string, unknown>
49
50
  }
50
51
 
51
52
  export interface CatalogAiToolDefinition<TInput = unknown, TOutput = unknown> {