Skip to content

PartnerRelationship — Lifecycle State Machine

Generated from specification/state-machines/partner-relationship.md. Edit the canonical source file, not this page.

RFC 2119 normative language applies throughout.

State Meaning
draft Relationship request assembled but not yet submitted to the accepting organization. Visible only to the requesting organization.
requested Submission sent; awaiting acceptance by the accepting organization. Both organizations can observe the relationship.
active Both sides have authorized the relationship. Capacity and load data sharing is enabled within the granted scopes.
suspended Temporarily deactivated. Data sharing is disabled; existing matched offers and requests are unaffected but no new sharing occurs.
terminated Permanently closed. Data sharing has ended. The record is retained for audit.

Terminal states: terminated

From State Command To State Notes
(none) POST /partner-relationships draft Initiating organization creates the relationship object.
draft submit (implicit on first POST /partner-relationships/{id}/request) requested Requesting organization submits to accepting org.
requested accept (POST /partner-relationships/{id}/accept) active Accepting organization approves.
requested reject (POST /partner-relationships/{id}/reject) terminated Accepting organization declines.
requested withdraw terminated Requesting organization withdraws before acceptance.
active suspend (POST /partner-relationships/{id}/suspend) suspended Either authorized organization suspends.
active terminate (POST /partner-relationships/{id}/terminate) terminated Either authorized organization terminates.
suspended reactivate (POST /partner-relationships/{id}/reactivate) active The organization that suspended it reactivates.
suspended terminate terminated Either authorized organization terminates while suspended.

Any command applied to a state not listed in the “From State” column above MUST return 422 Unprocessable Entity with error type urn:freyt:protocol:error:invalid-state-transition.

  • Authorization: Actor belongs to requestingOrganizationId.
  • Scope required: relationships:manage
  • Relationship state: N/A (creating new).
  • Version check: None required for initial submission.
  • Policy check: acceptingOrganizationId must be a known organization in the registry.
  • Authorization: Actor belongs to acceptingOrganizationId.
  • Scope required: relationships:manage
  • Version check: If-Match header MUST match current resourceVersion.
  • Policy check: Accepting organization’s policy must not prohibit the requested scopes.
  • Authorization: Actor belongs to acceptingOrganizationId.
  • Scope required: relationships:manage
  • Version check: If-Match header MUST match current resourceVersion.
  • Authorization: Actor belongs to requestingOrganizationId.
  • Scope required: relationships:manage
  • Version check: If-Match header MUST match current resourceVersion.
  • Authorization: Actor belongs to either requestingOrganizationId or acceptingOrganizationId.
  • Scope required: relationships:manage
  • Version check: If-Match header MUST match current resourceVersion.
  • Policy check: Suspension reason MUST be provided.

terminate (active | suspended → terminated)

Section titled “terminate (active | suspended → terminated)”
  • Authorization: Actor belongs to either participating organization.
  • Scope required: relationships:manage
  • Version check: If-Match header MUST match current resourceVersion.
  • Policy check: Termination reason MUST be provided.
  • Authorization: Actor belongs to the organization that issued the suspend command.
  • Scope required: relationships:manage
  • Version check: If-Match header MUST match current resourceVersion.
  • Policy check: If effectiveUntil has passed, reactivation MUST be rejected.
Command Postconditions
submit status set to requested; submittedAt timestamp recorded; event pcx.partner-relationship.requested.v1 emitted.
accept status set to active; effectiveFrom set to current time if not pre-set; resourceVersion incremented; event pcx.partner-relationship.activated.v1 emitted.
reject status set to terminated; terminatedAt recorded; rejection reason stored; event pcx.partner-relationship.terminated.v1 emitted.
withdraw status set to terminated; terminatedAt recorded; withdrawal reason stored; event emitted.
suspend status set to suspended; suspendedAt recorded; suspension reason stored; resourceVersion incremented; event pcx.partner-relationship.suspended.v1 emitted. Data sharing ceases immediately.
terminate status set to terminated; terminatedAt recorded; resourceVersion incremented; event pcx.partner-relationship.terminated.v1 emitted. Data sharing ceases immediately.
reactivate status set to active; reactivatedAt recorded; resourceVersion incremented; event pcx.partner-relationship.reactivated.v1 emitted.
  • All state-changing commands require If-Match with the current ETag.
  • Concurrent suspend and terminate on the same resource: the first writer wins; the second receives 409 Conflict with stale-resource-version.
  • Concurrent accept and withdraw: whichever commits first wins; the other receives 409.
  • The server MUST apply transitions atomically. A transition MUST NOT be partially committed.
  1. Uniqueness: At most one non-terminated PartnerRelationship may exist between a given (requestingOrganizationId, acceptingOrganizationId) pair at any time.
  2. Audit retention: Records in terminated state MUST be retained for the period defined in retentionPolicyRef and MUST NOT be physically deleted.
  3. Scope containment: scopes in an active relationship must be a subset of scopes granted by both organizations’ policies.
  4. Effective period: If effectiveUntil is set and the current time exceeds it, the relationship behaves as suspended for authorization checks even if status is active. A background job transitions it to terminated.
  5. No resurrection: A terminated relationship MUST NOT be transitioned to any other state. A new relationship may be created to replace it.
  6. Visibility isolation: A draft relationship MUST NOT be visible to the acceptingOrganizationId until status is requested.