---
id: ATS-PFM-INT-020
scope: CAP-PFM-INT-020
product_area: platform
module: integrations
revision: 3
status: proposed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  macroservice-libraries: 54536a441935c6e09fdb7f96f0bec71c52ba4e03
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-PFM-INT-020-01
    title: Draft ownership follows the selected event
    level: api
    proves:
      - BR-CAP-PFM-INT-020-01
    preconditions: The automation API can configure an overdue-invoice event.
    steps: 'Create its rule, replace the event before publication, publish and try another event change.'
    expected: >-
      Accounting owns the rule, the draft event change succeeds and the published rule refuses another
      event.
    negative: true
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to:
      - TST-PFM-INT-594
    provenance: test
    source: >-
      services-platform:modules/workflow-actions/tests/integration/services/persistence/automation-rules.integration.spec.js#creates
      the rule as a draft, owned by the event’s application, with its first version as the draft
    category: transition
    binding_evidence:
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/persistence/automation-rules.integration.spec.js#creates
        the rule as a draft, owned by the event’s application, with its first version as the draft
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/persistence/automation-rules.integration.spec.js#replaces
        a never-published rule’s name and event, deriving its application again
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/persistence/automation-rules.integration.spec.js#refuses
        to change a published rule’s event (409)
    binding_scope: >-
      contributions: the cited tests support their own asserted outcomes. Additional setup, branches
      and combined sequences remain proposed unless the cited assertions exercise them.
  - id: ATS-PFM-INT-020-02
    title: Draft versions are edited rather than multiplied
    level: api
    proves:
      - BR-CAP-PFM-INT-020-02
    preconditions: A rule already has a published version.
    steps: 'Save a new draft, update it and submit a stale update.'
    expected: 'The next version opens once, subsequent saves edit that draft and stale writes refuse.'
    negative: false
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to:
      - TST-PFM-INT-588
      - TST-PFM-INT-594
    provenance: test
    source: >-
      services-platform:modules/workflow-actions/tests/integration/db/workflow-actions-tables.integration.spec.js#refuses
      a second draft of one rule
    category: concurrency
    binding_evidence:
      - >-
        services-platform:modules/workflow-actions/tests/integration/db/workflow-actions-tables.integration.spec.js#refuses
        a second draft of one rule
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/persistence/automation-rules.integration.spec.js#opens
        the next version as the draft once the last is published
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/persistence/automation-rules.integration.spec.js#refuses
        a draft saved over a newer one (409)
    binding_scope: >-
      contributions: the cited tests support their own asserted outcomes. Additional setup, branches
      and combined sequences remain proposed unless the cited assertions exercise them.
  - id: ATS-PFM-INT-020-03
    title: Publication requires a runnable configuration and authority
    level: api
    proves:
      - BR-CAP-PFM-INT-020-03
      - AS-JNY-PFM-INT-006-01
    preconditions: An overdue-invoice rule remains draft.
    steps: >-
      Publish with an unknown event, undeclared fact, no action, wrong trigger and missing action
      permission, then correct it.
    expected: Each invalid publication names its problem; valid publication retains the necessary permissions.
    negative: true
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to:
      - TST-PFM-INT-589
    provenance: test
    source: >-
      services-platform:modules/workflow-actions/tests/integration/services/automation/publish-automation-rule.integration.spec.js#refuses
      a publisher without the permission an action’s type requires
    category: validation
    binding_evidence:
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/automation/publish-automation-rule.integration.spec.js#refuses
        a publisher without the permission an action’s type requires
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/automation/publish-automation-rule.integration.spec.js#refuses
        an event no application registers
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/automation/publish-automation-rule.integration.spec.js#refuses
        a condition over a fact the event does not declare
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/automation/publish-automation-rule.integration.spec.js#refuses
        a rule with no action
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/automation/publish-automation-rule.integration.spec.js#refuses
        an action configured at another trigger than the rule’s event
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/automation/publish-automation-rule.integration.spec.js#records
        the publisher and the permissions the actions required
    binding_scope: >-
      contributions: the cited tests support their own asserted outcomes. Additional setup, branches
      and combined sequences remain proposed unless the cited assertions exercise them.
  - id: ATS-PFM-INT-020-04
    title: Published content resists direct mutation
    level: api
    proves:
      - BR-CAP-PFM-INT-020-04
    preconditions: A rule version is published.
    steps: 'Attempt direct changes to actions, condition, fingerprint and publication fields.'
    expected: All content changes refuse while allowed system-column maintenance remains possible.
    negative: false
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to:
      - TST-PFM-INT-588
      - TST-PFM-INT-589
    provenance: test
    source: >-
      services-platform:modules/workflow-actions/tests/integration/db/workflow-actions-tables.integration.spec.js#refuses
      a change to a published version’s actions
    category: invariant
    binding_evidence:
      - >-
        services-platform:modules/workflow-actions/tests/integration/db/workflow-actions-tables.integration.spec.js#refuses
        a change to a published version’s actions
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/automation/publish-automation-rule.integration.spec.js#freezes
        the draft with the hash of its condition
      - >-
        services-platform:modules/workflow-actions/tests/integration/db/workflow-actions-tables.integration.spec.js#refuses
        a change to a published version’s condition
      - >-
        services-platform:modules/workflow-actions/tests/integration/db/workflow-actions-tables.integration.spec.js#refuses
        withdrawing a published version’s publication
    binding_scope: >-
      contributions: the cited tests support their own asserted outcomes. Additional setup, branches
      and combined sequences remain proposed unless the cited assertions exercise them.
  - id: ATS-PFM-INT-020-05
    title: Rule retirement preserves historical meaning
    level: api
    proves:
      - BR-CAP-PFM-INT-020-05
    preconditions: 'Prepare draft, enabled, disabled and retired rules.'
    steps: >-
      Enable a draft, toggle enabled and disabled, retire, move retired and delete published or
      unpublished rules.
    expected: >-
      Only permitted moves succeed; published rules retain history through retirement rather than
      deletion.
    negative: true
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to:
      - TST-PFM-INT-594
    provenance: test
    source: >-
      services-platform:modules/workflow-actions/tests/integration/services/persistence/automation-rules.integration.spec.js#refuses
      to delete a published rule, which is retired instead (409)
    category: transition
    binding_evidence:
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/persistence/automation-rules.integration.spec.js#refuses
        to delete a published rule, which is retired instead (409)
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/persistence/automation-rules.integration.spec.js#refuses
        to enable a draft rule, which only a publish enables (409)
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/persistence/automation-rules.integration.spec.js#refuses
        any move of a retired rule (409)
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/persistence/automation-rules.integration.spec.js#deletes
        a rule never published, with its draft
    binding_scope: >-
      contributions: the cited tests support their own asserted outcomes. Additional setup, branches
      and combined sequences remain proposed unless the cited assertions exercise them.
  - id: ATS-PFM-INT-020-06
    title: Automation uses the published version once per event
    level: api
    proves:
      - BR-CAP-PFM-INT-020-06
    preconditions: 'An enabled rule has a newer draft, alongside a disabled rule.'
    steps: Raise the same event twice.
    expected: Only the enabled published version raises actions once and attributes them to its rule and version.
    negative: false
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to:
      - TST-PFM-INT-003
      - TST-PFM-INT-007
    provenance: test
    source: >-
      macroservice-libraries:packages/workflow-actions/src/tests/integration/automation.integration.spec.ts#raises
      each matching rule’s actions as platform.automation_rule, rule and version, at event, once per
      event
    category: rule
    binding_evidence:
      - >-
        macroservice-libraries:packages/workflow-actions/src/tests/integration/automation.integration.spec.ts#raises
        each matching rule’s actions as platform.automation_rule, rule and version, at event, once per
        event
      - >-
        macroservice-libraries:packages/workflow-actions/src/tests/integration/automation.integration.spec.ts#the
        documented read: enabled rules for the key, at their current published version, in the tenant
        only
      - >-
        macroservice-libraries:packages/workflow-actions/src/tests/integration/raise.integration.spec.ts#writes
        nothing on a repeated raise of the same occurrence: it finds its rows
    binding_scope: >-
      contributions: the cited tests support their own asserted outcomes. Additional setup, branches
      and combined sequences remain proposed unless the cited assertions exercise them.
  - id: ATS-PFM-INT-020-07
    title: Cross-application views tolerate an unavailable host
    level: api
    proves:
      - BR-CAP-PFM-INT-020-07
    preconditions: Two hosts expose views and one lacks a required column.
    steps: 'Read runs, timers and attention filters.'
    expected: >-
      The sound host returns ordered work and failed or blocked attention items, while the incompatible
      host is skipped with a warning.
    negative: false
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to:
      - TST-PFM-INT-598
    provenance: test
    source: >-
      services-platform:modules/workflow-actions/tests/integration/services/persistence/cross-workflow-views.queries.integration.spec.js#skips
      a host with no view, and one whose view lacks a column, naming each
    category: failure
    binding_evidence:
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/persistence/cross-workflow-views.queries.integration.spec.js#skips
        a host with no view, and one whose view lacks a column, naming each
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/persistence/cross-workflow-views.queries.integration.spec.js#answers
        the failed runs as needing attention
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/persistence/cross-workflow-views.queries.integration.spec.js#answers
        the blocked timers as needing attention
      - >-
        services-platform:modules/workflow-actions/tests/integration/services/persistence/cross-workflow-views.queries.integration.spec.js#answers
        the tenant its own runs alone, newest first
    binding_scope: >-
      contributions: the cited tests support their own asserted outcomes. Additional setup, branches
      and combined sequences remain proposed unless the cited assertions exercise them.
  - id: ATS-PFM-INT-020-08
    title: Read authority does not grant automation operation
    level: api
    proves:
      - BR-CAP-PFM-INT-020-09
    preconditions: Prepare a registry reader and a person lacking run-read.
    steps: Publish as the reader and inspect runs as the other person.
    expected: Both requests deny access.
    negative: true
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to:
      - TST-PFM-INT-587
    provenance: test
    source: >-
      services-platform:modules/workflow-actions/tests/e2e/workflow-actions.e2e.spec.js#refuses a reader
      the publish (403)
    category: permission
    binding_evidence:
      - >-
        services-platform:modules/workflow-actions/tests/e2e/workflow-actions.e2e.spec.js#refuses a
        reader the publish (403)
      - >-
        services-platform:modules/workflow-actions/tests/e2e/workflow-actions.e2e.spec.js#refuses a
        caller without runs-read (403)
    binding_scope: >-
      contributions: the cited tests support their own asserted outcomes. Additional setup, branches
      and combined sequences remain proposed unless the cited assertions exercise them.
  - id: ATS-PFM-INT-020-09
    level: api
    negative: true
    data_needs: Run-owned records and principals in an isolated workspace.
    bound_to: []
    provenance: proposed
    title: Exercise the complete automation rule lifecycle
    category: transition
    proves:
      - BR-CAP-PFM-INT-020-01
      - BR-CAP-PFM-INT-020-02
      - BR-CAP-PFM-INT-020-03
      - BR-CAP-PFM-INT-020-04
      - BR-CAP-PFM-INT-020-05
    preconditions: >-
      Prepare one independent record in each starting state, including absent-record cases where the
      model defines creation.
    steps: >-
      Run each listed transition once with its guard satisfied, then repeat it with the guard denied.
      Inspect the resulting record and listed side effects after commit.
    expected: >-
      Each positive case reaches its listed destination and records its defined side effects. Each denied
      case preserves the starting record and creates no transition side effects.
    source: >-
      rhythm-v2-docs:specs/platform/integrations/design/state-models/STATE-PFM-INT-015-automation-rule-lifecycle.md#transitions
    state_model: STATE-PFM-INT-015
    transition_cases:
      - from: draft
        to: draft
        trigger: Save unpublished content
        guard: The read version matches and the rule remains editable
        side_effects:
          - Update the first draft’s content.
        provenance: proposed
        source: 'services-platform:modules/workflow-actions/services/persistence/automation-rules.ts'
      - from: draft
        to: enabled
        trigger: Publish the first version
        guard: 'Registered event, condition facts, valid actions and publisher authority checks pass'
        side_effects:
          - Freeze content and publication attribution
          - Record permissions and select the current version.
        provenance: proposed
        source: 'services-platform:modules/workflow-actions/services/persistence/automation-rules.ts'
      - from: enabled
        to: enabled
        trigger: Publish a replacement version
        guard: A new draft exists and ordinary publication checks pass
        side_effects:
          - Freeze the replacement and move the current publication.
        provenance: proposed
        source: 'services-platform:modules/workflow-actions/services/persistence/automation-rules.ts'
      - from: enabled
        to: disabled
        trigger: Pause published automation
        guard: The rule remains enabled
        side_effects:
          - Exclude the rule from subsequent event reads.
        provenance: proposed
        source: 'services-platform:modules/workflow-actions/services/persistence/automation-rules.ts'
      - from: disabled
        to: enabled
        trigger: Restore paused automation
        guard: The rule remains disabled
        side_effects:
          - Use its current publication for subsequent events.
        provenance: proposed
        source: 'services-platform:modules/workflow-actions/services/persistence/automation-rules.ts'
      - from: disabled
        to: disabled
        trigger: Publish while paused
        guard: A draft exists and ordinary publication checks pass
        side_effects:
          - Update the current publication without enabling the rule.
        provenance: proposed
        source: 'services-platform:modules/workflow-actions/services/automation/publish-automation-rule.ts'
      - from: draft
        to: retired
        trigger: Retire unpublished automation
        guard: The rule is not already retired
        side_effects:
          - Keep the rule as a retired record.
        provenance: proposed
        source: 'services-platform:modules/workflow-actions/services/persistence/automation-rules.ts'
      - from: enabled
        to: retired
        trigger: Retire usable automation
        guard: The rule is not already retired
        side_effects:
          - Keep the rule and version references used by host runs.
        provenance: proposed
        source: 'services-platform:modules/workflow-actions/services/persistence/automation-rules.ts'
      - from: disabled
        to: retired
        trigger: Retire paused automation
        guard: The rule is not already retired
        side_effects:
          - Keep the rule and version references used by host runs.
        provenance: proposed
        source: 'services-platform:modules/workflow-actions/services/persistence/automation-rules.ts'
      - from: draft
        to: deleted
        trigger: Delete never-published automation
        guard: The rule has no publication history
        side_effects:
          - Remove its retained draft and rule record.
        provenance: proposed
        source: 'services-platform:modules/workflow-actions/services/persistence/automation-rules.ts'
    proof_boundary: >-
      The parameterized cases prove the listed lifecycle outcomes. Separate assertions are needed for
      independent object invariants, numeric limits and simultaneous requests.
  - id: ATS-PFM-INT-020-10
    level: api
    negative: false
    data_needs: Run-owned records and principals in an isolated workspace.
    bound_to: []
    provenance: proposed
    title: Recipe edits leave a published automation unchanged
    category: interaction
    proves:
      - BR-CAP-PFM-INT-019-04
      - BR-CAP-PFM-INT-020-04
    exercises:
      - CAP-PFM-INT-020
      - CAP-PFM-INT-019
    preconditions: A rule publishes actions copied from a customer recipe.
    steps: 'Edit the recipe, inspect the published version and raise its event.'
    expected: >-
      Published content and raised work keep the copied actions until an explicit new version is
      published.
    source:
      - >-
        services-platform:docs/workflow-actions/README.md#Workflow actions: Platform's part of the
        Workflow Action Engine
      - >-
        services-platform:modules/workflow-actions/tests/integration/db/workflow-actions-tables.integration.spec.js#refuses
        a change to a published version’s actions
    workflows: []
evidence:
  - >-
    Each binding identifies an existing source test at the pinned revision; unbound scenarios remain
    proposed proof obligations.
coverage:
  rule: covered
  transition: covered
  validation: covered
  permission: covered
  edge: 'gap: FND-PFM-INT-090'
  failure: covered
  boundary: 'gap: FND-PFM-INT-090'
  concurrency: covered
  invariant: covered
  interaction: covered
coverage_notes:
  covered: A designed scenario exists; executable coverage and a passing run require separate evidence.
  gaps: >-
    The finding records categories without a designed scenario and remaining permission and rule audit
    obligations.
---
# Publish event-driven automation and follow its work: Capability Test Specification

## Coverage

| Rule | Proved By |
|---|---|
| `BR-CAP-PFM-INT-020-01` | `ATS-PFM-INT-020-01`, `ATS-PFM-INT-020-09` |
| `BR-CAP-PFM-INT-020-02` | `ATS-PFM-INT-020-02`, `ATS-PFM-INT-020-09` |
| `BR-CAP-PFM-INT-020-03` | `ATS-PFM-INT-020-03`, `ATS-PFM-INT-020-09` |
| `BR-CAP-PFM-INT-020-04` | `ATS-PFM-INT-020-04`, `ATS-PFM-INT-020-09`, `ATS-PFM-INT-020-10` |
| `BR-CAP-PFM-INT-020-05` | `ATS-PFM-INT-020-05`, `ATS-PFM-INT-020-09` |
| `BR-CAP-PFM-INT-020-06` | `ATS-PFM-INT-020-06` |
| `BR-CAP-PFM-INT-020-07` | `ATS-PFM-INT-020-07` |
| `BR-CAP-PFM-INT-020-09` | `ATS-PFM-INT-020-08` |

## Interactions With Related Capabilities

Automation publication depends on the current action registry and the configured recipe. The interaction cases check permission refusal, declaration retirement and the effect of later configuration changes on published work.

The structured scenarios name the capabilities and rules involved. A bound test contributes only the outcomes it asserts; proposed transition matrices and composed interactions still require executable proof.
