Migrate workflow executions onto the unified job system (single-job wrap).
WorkflowEngine is split into _create_execution (validate graph + persist the
running WorkflowExecution row) + run_execution (the synchronous DAG core) +
enqueue_execution (create row, enqueue a 'workflow.execute' job, return the
execution id immediately). execute_workflow stays as the synchronous primitive.
- All four triggers route through enqueue_execution: manual API, webhook,
cron tick (builtin.workflow_schedules), and the WorkflowEventBus. The manual
and webhook endpoints no longer block the HTTP request on the whole DAG; the
cron tick enqueues one job per due workflow instead of running them serially
inside the tick; the event bus thread now only matches + enqueues.
- max_attempts=1 (workflows deploy/script/notify — not idempotent). A failed
run raises so the unified job is marked failed; the WorkflowExecution row
keeps the detailed per-node status/logs. Graph validation still happens
synchronously at enqueue, so an invalid workflow surfaces immediately.
- tests: register, enqueue-creates-row+job, empty workflow runs to success,
failure path marks the job failed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>