---
id: ATS-PFM-INT-001
scope: CAP-PFM-INT-001
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-001-01
    title: Cross-provider release registration is refused
    level: api
    proves:
      - BR-CAP-PFM-INT-001-01
    preconditions: Two adapter principals and a registered non-adapter service are available.
    steps: >-
      Attempt registration for another adapter, from a non-adapter service and from Platform in
      production and development.
    expected: >-
      Foreign and non-adapter principals receive access denial, Platform is refused in production and
      admitted in development, and refused requests save nothing.
    negative: true
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to:
      - TST-PFM-INT-563
      - TST-PFM-INT-582
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/registration/register-integration-version.integration.spec.js#refuses
      an adapter principal registering another adapter’s key (403), and writes nothing
    category: permission
    binding_evidence:
      - >-
        services-platform:modules/integrations/tests/integration/services/registration/register-integration-version.integration.spec.js#refuses
        an adapter principal registering another adapter’s key (403), and writes nothing
      - >-
        services-platform:modules/integrations/tests/integration/services/registration/register-integration-version.integration.spec.js#refuses
        a principal that is neither an adapter nor registered (403), and writes nothing
      - >-
        services-platform:modules/integrations/tests/integration/services/registration/register-integration-version.integration.spec.js#refuses
        a registered service that is not an adapter (403), and writes nothing
      - >-
        services-platform:modules/integrations/tests/unit/services/registration-rules.spec.ts#refuses
        svc_platform in production
      - >-
        services-platform:modules/integrations/tests/integration/services/registration/register-integration-version.integration.spec.js#ignores
        an adapter header the caller sent, so no caller can claim an adapter’s name
    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-001-02
    title: Invalid release descriptions leave no partial registration
    level: api
    proves:
      - BR-CAP-PFM-INT-001-02
    preconditions: Prepare a valid release from the test adapter.
    steps: >-
      Alter the fingerprint, capability major, feature, contract-package version and manifest shape
      independently.
    expected: >-
      Each invalid package reports its problem without creating definition, version or capability
      records.
    negative: true
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to:
      - TST-PFM-INT-563
      - TST-PFM-INT-582
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/registration/register-integration-version.integration.spec.js#refuses
      a hash that is not the manifest’s, and writes nothing
    category: validation
    binding_evidence:
      - >-
        services-platform:modules/integrations/tests/integration/services/registration/register-integration-version.integration.spec.js#refuses
        a hash that is not the manifest’s, and writes nothing
      - >-
        services-platform:modules/integrations/tests/integration/services/registration/register-integration-version.integration.spec.js#refuses
        a capability major the contracts do not define, naming it, and writes nothing
      - >-
        services-platform:modules/integrations/tests/integration/services/registration/register-integration-version.integration.spec.js#refuses
        a manifest the schema refuses, and writes nothing
      - >-
        services-platform:modules/integrations/tests/unit/services/registration-rules.spec.ts#refuse
        contracts newer than the ones Platform is built with
      - >-
        services-platform:modules/integrations/tests/unit/services/registration-rules.spec.ts#refuse a
        feature the capability does not define
    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-001-03
    title: First registration remains internal
    level: api
    proves:
      - BR-CAP-PFM-INT-001-03
    preconditions: The test adapter has no catalogue definition.
    steps: Register its initial release.
    expected: A new internal definition exists and is absent from customer catalogues.
    negative: false
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to:
      - TST-PFM-INT-563
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/registration/register-integration-version.integration.spec.js#creates
      the definition by its key, internal until Rhythm offers it
    category: rule
    binding_evidence:
      - >-
        services-platform:modules/integrations/tests/integration/services/registration/register-integration-version.integration.spec.js#creates
        the definition by its key, internal until Rhythm offers it
    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-001-04
    title: Published manifests survive conflicting registration
    level: api
    proves:
      - BR-CAP-PFM-INT-001-04
    preconditions: The adapter version is already published.
    steps: 'Register that version with a changed fingerprint, then submit the original manifest.'
    expected: >-
      The change conflicts and preserves the published fingerprint; the identical version remains the
      sole unchanged version.
    negative: true
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to:
      - TST-PFM-INT-563
      - TST-PFM-INT-562
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/registration/register-integration-version.integration.spec.js#refuses
      a published version registered again with another hash (409), and keeps the published hash
    category: invariant
    binding_evidence:
      - >-
        services-platform:modules/integrations/tests/integration/services/registration/register-integration-version.integration.spec.js#refuses
        a published version registered again with another hash (409), and keeps the published hash
      - >-
        services-platform:modules/integrations/tests/integration/services/registration/cli-registration-contract.integration.spec.js#answers
        unchanged and keeps the one version (idempotent)
      - >-
        services-platform:modules/integrations/tests/integration/services/registration/cli-registration-contract.integration.spec.js#answers
        409 and keeps the published hash
    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-001-05
    title: Replacement deployments drain their predecessor
    level: api
    proves:
      - BR-CAP-PFM-INT-001-05
    preconditions: A registered release has an active deployment.
    steps: 'Register another deployment, then attempt a direct second active deployment in that environment.'
    expected: >-
      Replacement drains the old deployment; the database rejects simultaneous active deployments for the
      same release and environment.
    negative: false
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to:
      - TST-PFM-INT-563
      - TST-PFM-INT-503
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/registration/register-integration-version.integration.spec.js#drains
      the deployment it replaces
    category: concurrency
    binding_evidence:
      - >-
        services-platform:modules/integrations/tests/integration/services/registration/register-integration-version.integration.spec.js#drains
        the deployment it replaces
      - >-
        services-platform:modules/integrations/tests/integration/db/integration-deployments.table.integration.spec.js#refuses
        a second active deployment of a version in an environment
    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-001-06
    title: Version lifecycle refuses skipped states
    level: api
    proves:
      - BR-CAP-PFM-INT-001-06
    preconditions: Begin with a validated release.
    steps: 'Attempt direct retirement, then publish, deprecate and retire in order.'
    expected: Skipped retirement reports the invalid state; permitted transitions save their timestamps.
    negative: true
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to: []
    provenance: proposed
    source: >-
      services-platform:modules/integrations/services/persistence/integration-versions.ts:VERSION_TRANSITIONS
    category: transition
    binding_evidence: []
  - id: ATS-PFM-INT-001-07
    title: Pinned releases remain available
    level: api
    proves:
      - BR-CAP-PFM-INT-001-07
    preconditions: A deprecated release still serves an active workspace connection.
    steps: 'Attempt retirement, disconnect the connection and request retirement again.'
    expected: Retirement first reports its dependent connection count and succeeds when that count reaches zero.
    negative: true
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to: []
    provenance: proposed
    source: >-
      services-platform:modules/integrations/services/persistence/integration-versions.ts:pinnedConnectionCount
    category: edge
    binding_evidence: []
  - id: ATS-PFM-INT-001-08
    title: Publication updates the current release correctly
    level: api
    proves:
      - BR-CAP-PFM-INT-001-08
    preconditions: An integration has a published earlier release and a validated newer release.
    steps: >-
      Publish the newer release, then attempt publication of an older validated release; repeat with the
      current release deprecated.
    expected: >-
      The newer publication becomes current; an older publication does not replace a still-published
      current release, but can replace a deprecated current release.
    negative: false
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to: []
    provenance: proposed
    source: >-
      services-platform:modules/integrations/services/persistence/integration-versions.ts:moveCurrentVersionIfNewest
    category: rule
    binding_evidence: []
  - id: ATS-PFM-INT-001-09
    title: Availability grants replace the customer audience
    level: api
    proves:
      - BR-CAP-PFM-INT-001-09
    preconditions: A published integration can be offered to customers.
    steps: 'Restrict it to one workspace, replace that grant list and submit grants with public availability.'
    expected: >-
      Restricted grants match the replacement list, and public availability refuses a customer grant
      list.
    negative: false
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to:
      - TST-PFM-INT-515
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/catalog/catalog.integration.spec.js#replaces
      the whole list of grants
    category: boundary
    binding_evidence:
      - >-
        services-platform:modules/integrations/tests/integration/services/catalog/catalog.integration.spec.js#replaces
        the whole list of grants
      - >-
        services-platform:modules/integrations/tests/integration/services/catalog/catalog.integration.spec.js#refuses
        a list of tenants for an integration that is not restricted
      - >-
        services-platform:modules/integrations/tests/integration/services/catalog/catalog.integration.spec.js#answers
        the tenants a restricted definition is offered to
    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-001-10
    title: Staff catalogue rejects customer callers
    level: api
    proves:
      - BR-CAP-PFM-INT-001-10
    preconditions: A staff operator and a workspace administrator are authenticated.
    steps: Read the staff catalogue with each identity.
    expected: >-
      The operator receives definitions, versions and deployments regardless of availability; the
      customer receives access denied.
    negative: true
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to:
      - TST-PFM-INT-489
      - TST-PFM-INT-515
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/e2e/integrations.e2e.spec.js#is refused Rhythm HQ’s
      catalog (403)
    category: permission
    binding_evidence:
      - >-
        services-platform:modules/integrations/tests/e2e/integrations.e2e.spec.js#is refused Rhythm HQ’s
        catalog (403)
      - >-
        services-platform:modules/integrations/tests/e2e/integrations.e2e.spec.js#reads Rhythm HQ’s
        catalog
      - >-
        services-platform:modules/integrations/tests/integration/services/catalog/catalog.integration.spec.js#answers
        every definition, whatever its availability, with its versions and deployments
    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-001-11
    title: Staff secrets remain write-only
    level: api
    proves:
      - BR-CAP-PFM-INT-001-11
    preconditions: The integration declares a platform-secret purpose.
    steps: >-
      List its secret facts, replace the secret, write an undeclared purpose and repeat as a customer
      administrator.
    expected: >-
      Only purpose and version facts return; a valid write is audited without its value, and undeclared
      purposes and customer writes refuse.
    negative: true
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to:
      - TST-PFM-INT-486
      - TST-PFM-INT-534
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/e2e/credentials.e2e.spec.js#lists the integration’s
      declared secrets by name and version, never a value
    category: permission
    binding_evidence:
      - >-
        services-platform:modules/integrations/tests/e2e/credentials.e2e.spec.js#lists the integration’s
        declared secrets by name and version, never a value
      - >-
        services-platform:modules/integrations/tests/e2e/credentials.e2e.spec.js#refuses a purpose the
        integration does not declare
      - >-
        services-platform:modules/integrations/tests/e2e/credentials.e2e.spec.js#is refused to a tenant’s
        administrator
      - >-
        services-platform:modules/integrations/tests/integration/services/credentials/platform-secret-audit.integration.spec.js#INT-ACC-0533
        steps 1-4: no row holds a value
    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-001-12
    title: Deployment metadata is validated before registration
    level: api
    proves:
      - BR-CAP-PFM-INT-001-12
    preconditions: Prepare a valid adapter manifest and deployment.
    steps: >-
      Change its principal, runtime and environment, request external hosting, duplicate a capability and
      declare an incompatible execution mode.
    expected: Every altered declaration is rejected with its cause and leaves release records unchanged.
    negative: true
    data_needs: 'Fixtures establishing the stated accounts, declarations and history in an isolated workspace.'
    bound_to: []
    provenance: proposed
    source: >-
      services-platform:modules/integrations/services/registration/register-integration-version.ts:registerIntegrationVersion
    category: validation
    binding_evidence: []
  - id: ATS-PFM-INT-001-13
    level: api
    negative: true
    data_needs: Run-owned records and principals in an isolated workspace.
    bound_to: []
    provenance: proposed
    title: Exercise the complete integration release lifecycle
    category: transition
    proves:
      - BR-CAP-PFM-INT-001-02
      - BR-CAP-PFM-INT-001-04
      - BR-CAP-PFM-INT-001-06
    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-001-integration-release-lifecycle.md#transitions
    state_model: STATE-PFM-INT-001
    transition_cases:
      - from: absent
        to: validated
        trigger: Register without release publication
        guard: Manifest and runtime validation pass and the caller has adapter authority
        side_effects:
          - Save a first definition with internal availability
          - Save capability entries and replace the environment deployment.
        provenance: proposed
        source: >-
          services-platform:modules/integrations/tests/integration/services/registration/register-integration-version.integration.spec.js#refuses
          a hash that is not the manifest’s, and writes nothing
      - from: absent
        to: published
        trigger: Register for immediate publication
        guard: Registration passes its manifest and authority checks
        side_effects:
          - Stamp publication and update the current pointer when eligible.
        provenance: proposed
        source: >-
          services-platform:modules/integrations/services/persistence/integration-versions.ts:writeRegisteredVersion
      - from: validated
        to: validated
        trigger: Replace an unpublished declaration
        guard: The existing version remains mutable
        side_effects:
          - 'Replace the release manifest, capabilities and deployment.'
        provenance: proposed
        source: >-
          services-platform:modules/integrations/services/persistence/integration-versions.ts:writeRegisteredVersion
      - from: published
        to: published
        trigger: Redeploy an immutable release
        guard: The manifest fingerprint matches the retained release
        side_effects:
          - Keep release content and update the deployment.
        provenance: proposed
        source: >-
          services-platform:modules/integrations/services/persistence/integration-versions.ts:writeRegisteredVersion
      - from: validated
        to: published
        trigger: Publish through staff administration
        guard: The locked release remains validated
        side_effects:
          - Record publication and advance an eligible current pointer.
        provenance: proposed
        source: >-
          services-platform:modules/integrations/services/persistence/integration-versions.ts:transitionIntegrationVersion
      - from: published
        to: deprecated
        trigger: Deprecate through staff administration
        guard: The locked release remains published
        side_effects:
          - Record deprecation while leaving the current pointer unchanged.
        provenance: proposed
        source: >-
          services-platform:modules/integrations/services/persistence/integration-versions.ts:transitionIntegrationVersion
      - from: deprecated
        to: retired
        trigger: Retire through staff administration
        guard: The deprecated release has no non-disconnected connection pin in any workspace
        side_effects:
          - Read the cross-workspace pin count before recording retirement.
        provenance: proposed
        source: >-
          services-platform:modules/integrations/services/persistence/integration-versions.ts:pinnedConnectionCount
    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-001-14
    level: api
    negative: false
    data_needs: Run-owned records and principals in an isolated workspace.
    bound_to: []
    provenance: proposed
    title: A changed audience changes discovery
    category: interaction
    proves:
      - BR-CAP-PFM-INT-001-09
      - BR-CAP-PFM-INT-002-01
    exercises:
      - CAP-PFM-INT-001
      - CAP-PFM-INT-002
    preconditions: A published offer is public and two workspaces can see it.
    steps: >-
      Restrict the offer to the first workspace, replace the grant with the second, and read both
      catalogues after each change.
    expected: >-
      Only the currently granted workspace sees the offer; direct reads from the other workspace report
      absence.
    source:
      - >-
        services-platform:modules/integrations/tests/integration/services/catalog/catalog.integration.spec.js#replaces
        the whole list of grants
      - >-
        services-platform:modules/integrations/tests/integration/services/catalog/catalog.integration.spec.js#shows
        a restricted integration only to the tenant granted it
    workflows: []
  - id: ATS-PFM-INT-001-15
    level: api
    negative: false
    data_needs: Run-owned records and principals in an isolated workspace.
    bound_to: []
    provenance: proposed
    title: Connection pins constrain release retirement
    category: interaction
    proves:
      - BR-CAP-PFM-INT-001-07
      - BR-CAP-PFM-INT-004-10
    exercises:
      - CAP-PFM-INT-001
      - CAP-PFM-INT-004
    preconditions: >-
      A deprecated release has a verified connection pinned to it and a newer published release is
      available.
    steps: 'Attempt retirement, verify a move to the newer release, then attempt retirement again.'
    expected: >-
      The first retirement identifies the dependency; after the successful move the old release can
      retire.
    source:
      - >-
        services-platform:modules/integrations/services/persistence/integration-versions.ts:pinnedConnectionCount
      - >-
        services-platform:modules/integrations/services/connections/connection-operations.ts:requestVersionUpdate
    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: covered
  failure: 'gap: FND-PFM-INT-052'
  boundary: covered
  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 integration releases for eligible customers: Capability Test Specification

## Coverage

| Rule | Proved By |
|---|---|
| `BR-CAP-PFM-INT-001-01` | `ATS-PFM-INT-001-01` |
| `BR-CAP-PFM-INT-001-02` | `ATS-PFM-INT-001-02`, `ATS-PFM-INT-001-13` |
| `BR-CAP-PFM-INT-001-03` | `ATS-PFM-INT-001-03` |
| `BR-CAP-PFM-INT-001-04` | `ATS-PFM-INT-001-04`, `ATS-PFM-INT-001-13` |
| `BR-CAP-PFM-INT-001-05` | `ATS-PFM-INT-001-05` |
| `BR-CAP-PFM-INT-001-06` | `ATS-PFM-INT-001-06`, `ATS-PFM-INT-001-13` |
| `BR-CAP-PFM-INT-001-07` | `ATS-PFM-INT-001-07`, `ATS-PFM-INT-001-15` |
| `BR-CAP-PFM-INT-001-08` | `ATS-PFM-INT-001-08` |
| `BR-CAP-PFM-INT-001-09` | `ATS-PFM-INT-001-09`, `ATS-PFM-INT-001-14` |
| `BR-CAP-PFM-INT-001-10` | `ATS-PFM-INT-001-10` |
| `BR-CAP-PFM-INT-001-11` | `ATS-PFM-INT-001-11` |
| `BR-CAP-PFM-INT-001-12` | `ATS-PFM-INT-001-12` |

## Interactions With Related Capabilities

Release registration, customer discovery and installation meet at the catalogue boundary. The interaction cases follow a changed offer through existing adoption and a fresh installation attempt, keeping retained customer records separate from eligibility for new use.

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.
