---
id: WF-PFM-OPS-001
title: Submit a background job and start its execution
product_area: platform
module: operations
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
inference: []
trigger: An owning capability submits work that must continue beyond its initiating request.
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  macroservice-libraries: 54536a441935c6e09fdb7f96f0bec71c52ba4e03
implements:
  - CAP-PFM-OPS-001
moves:
  - STATE-PFM-OPS-001
  - STATE-PFM-OPS-002
crosses:
  - SVC-PFM-OPS-jobs
idempotency: >-
  Within a kind, the submission token identifies one intention. Outside a caller transaction a duplicate
  insertion resolves to the existing job; inside one, the losing transaction must be retried. A start with an
  existing handle returns the recorded run.
concurrency: >-
  Submission uniqueness prevents duplicate roots. Handle persistence uses a version-checked patch so an early
  task report is retained; orchestration names derive from the job identity.
hops:
  - 'n': 1
    actor_or_service: Owning module
    action: >-
      Insert the root, queued catalogue steps, initial history and submission audit inside the owner’s
      transaction.
    anchor: 'macroservice-libraries:packages/jobs/src/engine/job-engine.ts:createJob'
    seam: sync
    on_failure: Fail the capability and roll back its transaction.
    left_inconsistent: Neither the job nor its associated business rows remain.
    observer: Request’s error response and log is the observation surface.
    provenance: test
    source: >-
      macroservice-libraries:packages/jobs/src/engine/job-engine.spec.ts#refuses submitJob inside a
      transaction: the execution starts after the commit
  - 'n': 2
    actor_or_service: Owning module
    action: Commit the capability’s records and job as one database change.
    anchor: 'macroservice-libraries:packages/jobs/src/engine/job-engine.ts:createJob'
    seam: sync
    on_failure: Abort the transaction if commit fails.
    left_inconsistent: No committed partial submission remains.
    observer: Request’s log is the observation surface.
    provenance: documented
    source: 'services-platform:docs/jobs.md#2. Adding a job: tenant-portal onboarding as the example'
  - 'n': 3
    actor_or_service: Job engine
    action: >-
      Start orchestration after commit, carry the documented references and context, then patch the execution
      handle.
    anchor: 'macroservice-libraries:packages/jobs/src/engine/job-engine.ts:startJob'
    seam: state_machine
    on_failure: >-
      The forgiving helper logs and returns the job; strict callers propagate the error for caller or
      orchestration recovery.
    left_inconsistent: Business records and a pending job may exist without a recorded execution handle.
    observer: 'Start-error and abandoned-start logs; subsequently, the reconciled job detail.'
    provenance: observed
    source: 'macroservice-libraries:packages/jobs/src/engine/job-engine.ts:startJobOrLeaveToReconciler'
  - 'n': 4
    actor_or_service: Reconciler
    action: >-
      Reconcile an eligible job lacking an execution handle as never started and apply its declared failure
      effect.
    anchor: 'macroservice-libraries:packages/jobs/src/reconciler/job-reconciler.ts:handleCandidate'
    seam: schedule
    on_failure: Leave a failed candidate attempt for another eligible pass.
    left_inconsistent: >-
      The pending record remains until a successful pass; the usual near-twenty-minute consideration is not a
      deadline.
    observer: Job’s history and the monitors is the observation surface.
    provenance: test
    source: >-
      services-platform:modules/jobs/tests/integration/lifecycle/job-reconciliation/job-reconciliation.integration.spec.js#settles
      it failed, saying the job never started
branches:
  - condition: The caller has no transaction of its own
    path: 'The combined submission helper records and starts the job, propagating a start error.'
waits:
  - what: Reconciliation of a job that never started
    how_long: 'fifteen minutes of silence, checked every five minutes'
evidence:
  - >-
    macroservice-libraries at 54536a4: engine/job-engine.ts (submitJob, createJob, startJob,
    startJobOrLeaveToReconciler), engine/start-job-execution.ts.
  - >-
    services-platform at ad3f6a6: docs/jobs.md §2 step 8;
    modules/tenants/services/provisioning/submit-tenant-provisioning.ts.
  - >-
    codex examination 2026-10-23: checked the pinned source anchors, planning references and enforcement
    boundaries; unresolved limits are recorded in module findings.
controls: [TC-AVL-001, TC-AVL-004, TC-AVL-005, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-CRY-001, TC-CRY-002, TC-CRY-003, TC-CRY-004, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-004, TC-IAM-001, TC-IAM-002, TC-IAM-004, TC-IAM-005, TC-IAM-006, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-MON-001, TC-MON-002, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-004, TC-PI-005, TC-SEC-001, TC-SEC-002, TC-SEC-003, TC-SEC-004, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-VEN-001, TC-VEN-002, TC-VEN-003]
---

# Submit a background job and start its execution

## What It Does

Create the job beside the business change, then start its execution after commit. This lets operators inspect the submission even when orchestration cannot start. The engine requires callers to keep secrets and customer content out of execution inputs but does not validate arbitrary domain fields.

## The Flow

```mermaid
flowchart TD
  H0["Insert the root, queued catalogue steps, initial history and submission audit inside the owner’s transaction."]
  H1["Commit the capability’s records and job as one database change."]
  H0 --> H1
  H2["Start orchestration after commit, carry the documented references and context, then patch the execution handle."]
  H1 --> H2
  H3["Reconcile an eligible job lacking an execution handle as never started and apply its declared failure effect."]
  H2 --> H3
```

## When Something Fails

A failed submission transaction leaves no recorded business change or job. A failed start leaves both committed, with no recorded execution handle. Forgiving callers return the job; workspace provisioning retry uses the strict path and can report an error after commit. Reconciliation can later fail an unstarted run and invoke business recovery, subject to successful passes and candidate limits.

## Open Design Questions

Insertion conflicts inside a caller transaction require caller retry. The stronger input-safety obligation and start-recovery guarantees need the proof and limits recorded in findings.
