---
id: ATS-PFM-OPS-003
scope: CAP-PFM-OPS-003
product_area: platform
module: operations
revision: 2
status: proposed
approved_by: null
approved_at: null
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  macroservice-libraries: 54536a441935c6e09fdb7f96f0bec71c52ba4e03
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-PFM-OPS-003-01
    title: Address the recorded requester
    level: unit
    proves:
      - BR-CAP-PFM-OPS-003-02
    preconditions: One provisioning job names a person and another has no requester.
    steps: Run notification handling for both.
    expected: Only the named requester has a recipient message.
    negative: false
    data_needs: Controlled records and caller contexts matching this scenario’s preconditions.
    bound_to: []
    provenance: proposed
    source: >-
      services-platform:modules/jobs/tests/unit/services/notices/job-notice-email.spec.js#is addressed to
      the requester alone: the notice is about their own job
    evidence_candidates:
      - >-
        services-platform:modules/jobs/tests/unit/services/notices/job-notice-email.spec.js#is addressed
        to the requester alone: the notice is about their own job
    category: rule
  - id: ATS-PFM-OPS-003-02
    title: Suppress repeat completed notices
    level: api
    proves:
      - BR-CAP-PFM-OPS-003-03
      - INV-DOM-PFM-OPS-001-11
    preconditions: Delivered and suppressed outcome records already exist.
    steps: Request another claim for each.
    expected: Neither record is returned for sending or has its attempt count advanced.
    negative: true
    data_needs: Controlled records and caller contexts matching this scenario’s preconditions.
    bound_to:
      - TST-PFM-OPS-071
    provenance: test
    source: >-
      services-platform:modules/jobs/tests/integration/services/persistence/job-notices.integration.spec.js#answers
      nothing at all to the second claim, so nothing is sent twice
    evidence_candidates:
      - >-
        services-platform:modules/jobs/tests/integration/services/persistence/job-notices.integration.spec.js#answers
        nothing at all to the second claim, so nothing is sent twice
    category: invariant
    binding_evidence:
      - >-
        services-platform:modules/jobs/tests/integration/services/persistence/job-notices.integration.spec.js#answers
        nothing at all to the second claim, so nothing is sent twice
  - id: ATS-PFM-OPS-003-03
    title: Reclaim incomplete notices
    level: api
    proves:
      - BR-CAP-PFM-OPS-003-04
    preconditions: Pending and failed outcome records remain.
    steps: Claim them again.
    expected: The existing records become pending with another counted attempt and cleared error.
    negative: false
    data_needs: Controlled records and caller contexts matching this scenario’s preconditions.
    bound_to:
      - TST-PFM-OPS-071
    provenance: test
    source: >-
      services-platform:modules/jobs/tests/integration/services/persistence/job-notices.integration.spec.js#is
      claimed again, because a notice nobody received is worse than one that arrives twice
    evidence_candidates:
      - >-
        services-platform:modules/jobs/tests/integration/services/persistence/job-notices.integration.spec.js#is
        claimed again, because a notice nobody received is worse than one that arrives twice
    category: transition
    binding_evidence:
      - >-
        services-platform:modules/jobs/tests/integration/services/persistence/job-notices.integration.spec.js#is
        claimed again, because a notice nobody received is worse than one that arrives twice
  - id: ATS-PFM-OPS-003-04
    title: Isolate delivery failure from the job
    level: api
    proves:
      - BR-CAP-PFM-OPS-003-05
    preconditions: The email sender throws during notification.
    steps: Invoke requester notification.
    expected: No exception escapes and failure evidence is recorded and logged independently of the job.
    negative: true
    data_needs: Controlled records and caller contexts matching this scenario’s preconditions.
    bound_to: []
    provenance: proposed
    source: 'services-platform:modules/jobs/services/notices/notify-job-requester.ts:notifyJobRequester'
    category: failure
  - id: ATS-PFM-OPS-003-05
    title: Reach a requester without a started execution
    level: api
    proves:
      - BR-CAP-PFM-OPS-003-06
    preconditions: A notifying provisioning job has never begun.
    steps: Allow reconciliation to fail it.
    expected: The requester receives the reconciled failure explanation.
    negative: false
    data_needs: Controlled records and caller contexts matching this scenario’s preconditions.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/integration/lifecycle/reconciled-job-failure.integration.spec.js#tells
        the staff member who asked for the tenant that it failed, though no task of the job ever ran
      - TST-PFM-OPS-119
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/lifecycle/reconciled-job-failure.integration.spec.js#tells
      the staff member who asked for the tenant that it failed, though no task of the job ever ran
    category: interaction
    binding_evidence:
      - >-
        services-platform:modules/tenants/tests/integration/lifecycle/reconciled-job-failure.integration.spec.js#tells
        the staff member who asked for the tenant that it failed, though no task of the job ever ran
  - id: ATS-PFM-OPS-003-06
    title: Build the HQ link and environment label
    level: unit
    proves:
      - BR-CAP-PFM-OPS-003-07
    preconditions: The sending settings contain a console address and environment.
    steps: Render the requester notice.
    expected: The message identifies its environment and opens the matching HQ job page.
    negative: false
    data_needs: Controlled records and caller contexts matching this scenario’s preconditions.
    bound_to:
      - TST-PFM-OPS-079
    provenance: test
    source: >-
      services-platform:modules/jobs/tests/unit/services/notices/job-notice-email.spec.js#is the job’s
      own page in Rhythm HQ, by kind and id
    evidence_candidates:
      - >-
        services-platform:modules/jobs/tests/unit/services/notices/job-notice-email.spec.js#is the job’s
        own page in Rhythm HQ, by kind and id
    category: boundary
    binding_evidence:
      - >-
        services-platform:modules/jobs/tests/unit/services/notices/job-notice-email.spec.js#is the job’s
        own page in Rhythm HQ, by kind and id
  - id: ATS-PFM-OPS-003-07
    title: Keep reconciled provisioning recoverable
    level: api
    proves:
      - AS-JNY-PFM-OPS-002-01
      - AS-JNY-PFM-OPS-002-02
    preconditions: A provisioning job is stale without an execution.
    steps: Reconcile it and invoke the consequence again.
    expected: The workspace remains recoverably failed and the completed notice is not resent.
    negative: false
    data_needs: Controlled records and caller contexts matching this scenario’s preconditions.
    bound_to:
      - TST-PFM-OPS-119
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/lifecycle/reconciled-job-failure.integration.spec.js#sends
      the requester nothing a second time either
    evidence_candidates:
      - >-
        services-platform:modules/tenants/tests/integration/lifecycle/reconciled-job-failure.integration.spec.js#sends
        the requester nothing a second time either
      - >-
        services-platform:modules/tenants/tests/integration/lifecycle/reconciled-job-failure.integration.spec.js#moves
        the tenant to provisioning_failed, which is what makes it retryable and deletable again
    category: interaction
    binding_evidence:
      - >-
        services-platform:modules/tenants/tests/integration/lifecycle/reconciled-job-failure.integration.spec.js#sends
        the requester nothing a second time either
      - >-
        services-platform:modules/tenants/tests/integration/lifecycle/reconciled-job-failure.integration.spec.js#moves
        the tenant to provisioning_failed, which is what makes it retryable and deletable again
  - id: ATS-PFM-OPS-003-08
    title: Explain a never-started run to its requester
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-OPS-002-03
      - BR-CAP-PFM-OPS-003-06
    exercises:
      - CAP-PFM-OPS-003
      - CAP-PFM-OPS-002
    preconditions: A notifying provisioning run has no execution handle.
    steps: Reconcile the stale run and inspect its requester notice.
    expected: The message refers to the same failed run and carries its reconciliation explanation.
    negative: false
    data_needs: Isolated workspace records and caller contexts for both sides of the interaction.
    bound_to: []
    provenance: proposed
    source: >-
      services-platform:modules/jobs/tests/integration/lifecycle/job-reconciliation/job-reconciliation.integration.spec.js#settles
      it failed, saying the job never started;
      services-platform:modules/tenants/tests/integration/lifecycle/reconciled-job-failure.integration.spec.js#tells
      the staff member who asked for the tenant that it failed, though no task of the job ever ran;
      CAP-PFM-OPS-002; WF-PFM-OPS-002; WF-PFM-OPS-003; WF-PFM-OPS-004
  - id: ATS-PFM-OPS-003-09
    title: Retain lifecycle failure evidence
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-OPS-003-06
    exercises:
      - CAP-PFM-OPS-003
      - CAP-PFM-SEC-003
    preconditions: A workspace lifecycle run reaches an interrupted execution outcome.
    steps: Reconcile it and inspect the lifecycle record alongside the job record.
    expected: Both records identify the failed work without silently reopening its final history.
    negative: false
    data_needs: Isolated workspace records and caller contexts for both sides of the interaction.
    bound_to: []
    provenance: proposed
    source: >-
      services-platform:modules/tenants/tests/integration/lifecycle/reconciled-job-failure.integration.spec.js#tells
      the staff member who asked for the tenant that it failed, though no task of the job ever ran;
      CAP-PFM-SEC-003; WF-PFM-OPS-002; WF-PFM-OPS-003; WF-PFM-OPS-004
  - id: ATS-PFM-OPS-003-10
    title: Refuse incomplete notice configuration
    category: validation
    level: unit
    proves:
      - BR-CAP-PFM-OPS-003-09
    preconditions: The sending configuration lacks the from address in one case and the console address in another.
    steps: Resolve notice settings for both incomplete configurations.
    expected: Configuration validation prevents message construction and identifies the missing settings.
    negative: true
    data_needs: Run-owned records and controlled clocks or dependency responses named in the preconditions.
    bound_to:
      - TST-PFM-OPS-079
    provenance: test
    source: >-
      services-platform:modules/jobs/tests/unit/services/notices/job-notice-email.spec.js#refuses to send
      at all when the console is unset, so no notice links nowhere
  - id: ATS-PFM-OPS-003-11
    title: Record each delivery outcome before a later claim
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-OPS-003-03
      - BR-CAP-PFM-OPS-003-04
      - INV-DOM-PFM-OPS-001-11
    preconditions: >-
      Four separate pending notices can be recorded as delivered, suppressed or failed, or left
      unfinished.
    steps: 'Write the three outcomes, leave the fourth pending, and request another claim for each row.'
    expected: >-
      Delivered and suppressed notices refuse another claim; failed and unfinished notices return to
      pending with another counted attempt.
    negative: false
    data_needs: Run-owned records and controlled clocks or dependency responses named in the preconditions.
    bound_to:
      - TST-PFM-OPS-071
    provenance: test
    source: >-
      services-platform:modules/jobs/tests/integration/services/persistence/job-notices.integration.spec.js#claiming
      and settling the notice a job’s requester is sent
    models:
      - STATE-PFM-OPS-003
    transitions:
      - 1
      - 2
      - 3
      - 4
      - 5
  - id: ATS-PFM-OPS-003-12
    title: Keep success and failure notices distinct
    category: invariant
    level: api
    proves:
      - BR-CAP-PFM-OPS-003-10
      - INV-DOM-PFM-OPS-001-11
    preconditions: One run has no claimed success or failure notice.
    steps: Claim both outcome notices.
    expected: The two claims have different row identities and preserve their distinct outcome kinds.
    negative: false
    data_needs: Run-owned records and controlled clocks or dependency responses named in the preconditions.
    bound_to:
      - TST-PFM-OPS-071
    provenance: test
    source: >-
      services-platform:modules/jobs/tests/integration/services/persistence/job-notices.integration.spec.js#are
      separate notices, because the unique key is the job and the outcome together
  - id: ATS-PFM-OPS-003-13
    title: Claim a successful run’s notice again after delivery
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-OPS-003-03
      - BR-CAP-PFM-OPS-001-04
    exercises:
      - CAP-PFM-OPS-001
      - CAP-PFM-OPS-003
    workflows:
      - WF-PFM-OPS-002
    preconditions: A notifying run has succeeded and its requester message has a delivered outcome.
    steps: Invoke notification again for that same job outcome and inspect the run and notice.
    expected: The ordinary repeat does not send another message or change the final job.
    negative: false
    data_needs: >-
      Isolated workspace and run-owned lifecycle records, with a second linked workspace where shared
      company evidence is checked.
    bound_to: []
    provenance: proposed
    source: >-
      services-platform:modules/jobs/tests/integration/services/job-snapshot/job-snapshot.integration.spec.js#takes
      that catalog from the published event rather than the declaration, which the event itself carries;
      macroservice-libraries:packages/jobs/src/workflow/job-workflow.spec.ts#lets no detail of the
      transient error reach the job or the execution state;
      macroservice-libraries:packages/jobs/src/engine/job-engine.ts:settleJob;
      macroservice-libraries:packages/jobs/src/reconciler/job-reconciler.spec.ts#applies it before the
      settlement, so a consequence that fails leaves the job for the next pass;
      services-platform:modules/jobs/services/notices/notify-job-requester.ts:notifyJobRequester
evidence:
  - >-
    Pinned capability rules, object invariants, state transitions and workflows are reviewed for testing
    obligations.
  - >-
    Executable bindings refer only to existing suites; no module executable suite runs during this
    documentation job.
coverage:
  rule: covered
  transition: covered
  validation: covered
  permission: not-applicable
  edge: 'gap: FND-PFM-OPS-055'
  failure: covered
  boundary: covered
  concurrency: 'gap: FND-PFM-OPS-055'
  invariant: covered
  interaction: covered
coverage_notes:
  permission: >-
    This internal operation defines no independent caller permission; its callers and audience checks
    have separate scenarios.
  edge: 'Empty, missing and unusual inputs need dedicated proof.'
  concurrency: >-
    No controlled overlapping execution proves the capability’s read or write behavior while related
    state changes.
related_capabilities:
  - CAP-PFM-OPS-002
  - CAP-PFM-SEC-003
workflow_interactions:
  - WF-PFM-OPS-002
  - WF-PFM-OPS-003
  - WF-PFM-OPS-004
coverage_obligations:
  finding: FND-PFM-OPS-055
  uncovered_must_prove:
    - BR-CAP-PFM-OPS-003-11
  object_invariants_requiring_explicit_trace:
    - INV-DOM-PFM-OPS-001-01
    - INV-DOM-PFM-OPS-001-02
    - INV-DOM-PFM-OPS-001-03
    - INV-DOM-PFM-OPS-001-04
    - INV-DOM-PFM-OPS-001-05
    - INV-DOM-PFM-OPS-001-06
    - INV-DOM-PFM-OPS-001-07
    - INV-DOM-PFM-OPS-001-08
    - INV-DOM-PFM-OPS-001-09
    - INV-DOM-PFM-OPS-001-10
    - INV-DOM-PFM-OPS-001-12
  related_scenarios:
    - capabilities:
        - CAP-PFM-OPS-003
        - CAP-PFM-OPS-002
      scenario: ATS-PFM-OPS-003-08
    - capabilities:
        - CAP-PFM-OPS-003
        - CAP-PFM-SEC-003
      scenario: ATS-PFM-OPS-003-09
  unbound_scenarios:
    - ATS-PFM-OPS-003-01
    - ATS-PFM-OPS-003-04
    - ATS-PFM-OPS-003-08
    - ATS-PFM-OPS-003-09
    - ATS-PFM-OPS-003-13
  transition_review: []
  permission_review: []
  gap_detail: >-
    Missing jobs or recipient addresses and concurrent senders need complete notification-flow proof,
    including interrupted delivery-outcome writes.
workflow_scenarios:
  WF-PFM-OPS-002:
    - ATS-PFM-OPS-001-16
    - ATS-PFM-OPS-003-13
  WF-PFM-OPS-003:
    - ATS-PFM-OPS-004-11
---

# Notify a job’s requester of its outcome: Capability Test Specification

## Coverage

The category map distinguishes authored scenarios from unresolved proof obligations. A bound scenario names an existing executable suite; its recorded result remains unrun.

| Rule | Proof status |
|---|---|
| `BR-CAP-PFM-OPS-003-02` | `ATS-PFM-OPS-003-01` |
| `BR-CAP-PFM-OPS-003-03` | `ATS-PFM-OPS-003-02`, `ATS-PFM-OPS-003-11` |
| `BR-CAP-PFM-OPS-003-04` | `ATS-PFM-OPS-003-03`, `ATS-PFM-OPS-003-11` |
| `BR-CAP-PFM-OPS-003-05` | `ATS-PFM-OPS-003-04` |
| `BR-CAP-PFM-OPS-003-06` | `ATS-PFM-OPS-003-05`, `ATS-PFM-OPS-003-08`, `ATS-PFM-OPS-003-09` |
| `BR-CAP-PFM-OPS-003-07` | `ATS-PFM-OPS-003-06` |
| `BR-CAP-PFM-OPS-003-09` | `ATS-PFM-OPS-003-10` |
| `BR-CAP-PFM-OPS-003-11` | no scenario: `FND-PFM-OPS-055` |

## Interactions With Related Capabilities

Reach a requester without a started execution. The requester receives the reconciled failure explanation.

Keep reconciled provisioning recoverable. The workspace remains recoverably failed and the completed notice is not resent.

Explain a never-started run to its requester. The message refers to the same failed run and carries its reconciliation explanation.

Retain lifecycle failure evidence. Both records identify the failed work without silently reopening its final history.

Claim a successful run’s notice again after delivery. The ordinary repeat does not send another message or change the final job.

## Evidence and Boundaries

Pinned assertion sources support the listed executable bindings. Proposed cases retain the proof required beyond those boundaries. Structured obligations name incomplete object, transition and permission trace; row-level concurrency proof does not establish complete workflow serialization.
