---
id: STATE-PFM-MTD-006
title: Custom record publication
object: DOM-PFM-MTD-005
product_area: platform
module: metadata
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
states:
- name: unpublishable
  meaning: The object does not enable publication, so newly created records have no publication state.
- name: draft
  meaning: The record has not been published and is not designated for review.
- name: pending_review
  meaning: The record is designated for review and remains outside publication.
- name: published
  meaning: A publication timestamp is present; configured public consumption also depends on object access and property
    exposure.
- name: unpublished
  meaning: The record is outside publication after a withdrawal or an explicit selection of this state.
transitions:
- from: draft
  to: published
  trigger: An administrator selects published for the record.
  guard: The parent enables publication and is active; the record is unarchived, unlocked for updates and at the
    supplied version.
  side_effects:
  - Advance the version and audit the action; maintain the publication timestamp and append a published event.
  who: Records Administrator (platform.custom-records.publish)
  provenance: observed
  source: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:publishRecord
- from: pending_review
  to: published
  trigger: An administrator selects published for the record.
  guard: The parent enables publication and is active; the record is unarchived, unlocked for updates and at the
    supplied version.
  side_effects:
  - Advance the version and audit the action; maintain the publication timestamp and append a published event.
  who: Records Administrator (platform.custom-records.publish)
  provenance: observed
  source: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:publishRecord
- from: unpublished
  to: published
  trigger: An administrator selects published for the record.
  guard: The parent enables publication and is active; the record is unarchived, unlocked for updates and at the
    supplied version.
  side_effects:
  - Advance the version and audit the action; maintain the publication timestamp and append a published event.
  who: Records Administrator (platform.custom-records.publish)
  provenance: observed
  source: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:publishRecord
- from: published
  to: unpublished
  trigger: An administrator selects unpublished for the record.
  guard: The parent enables publication and is active; the record is unarchived, unlocked for updates and at the
    supplied version.
  side_effects:
  - Advance the version and audit the action; maintain the publication timestamp and append an unpublished event.
  who: Records Administrator (platform.custom-records.publish)
  provenance: observed
  source: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:publishRecord
- from: published
  to: draft
  trigger: An administrator selects draft for the record.
  guard: The parent enables publication and is active; the record is unarchived, unlocked for updates and at the
    supplied version.
  side_effects:
  - Advance the version and audit the action; maintain the publication timestamp and append an unpublished event.
  who: Records Administrator (platform.custom-records.publish)
  provenance: observed
  source: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:publishRecord
- from: published
  to: pending_review
  trigger: An administrator selects pending review for the record.
  guard: The parent enables publication and is active; the record is unarchived, unlocked for updates and at the
    supplied version.
  side_effects:
  - Advance the version and audit the action; maintain the publication timestamp and append an unpublished event.
  who: Records Administrator (platform.custom-records.publish)
  provenance: observed
  source: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:publishRecord
- from: draft
  to: pending_review
  trigger: An administrator selects pending review for the record.
  guard: The parent enables publication and is active; the record is unarchived, unlocked for updates and at the
    supplied version.
  side_effects:
  - Advance the version and audit the action; maintain the publication timestamp and append an updated event with
    no changed property keys.
  who: Records Administrator (platform.custom-records.publish)
  provenance: observed
  source: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:publishRecord
- from: pending_review
  to: draft
  trigger: An administrator selects draft for the record.
  guard: The parent enables publication and is active; the record is unarchived, unlocked for updates and at the
    supplied version.
  side_effects:
  - Advance the version and audit the action; maintain the publication timestamp and append an updated event with
    no changed property keys.
  who: Records Administrator (platform.custom-records.publish)
  provenance: observed
  source: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:publishRecord
- from: draft
  to: draft
  trigger: An administrator selects draft for the record.
  guard: The parent enables publication and is active; the record is unarchived, unlocked for updates and at the
    supplied version.
  side_effects:
  - Advance the version and audit the action; maintain the publication timestamp and append no business event.
  who: Records Administrator (platform.custom-records.publish)
  provenance: observed
  source: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:publishRecord
- from: draft
  to: unpublished
  trigger: An administrator selects unpublished for the record.
  guard: The parent enables publication and is active; the record is unarchived, unlocked for updates and at the
    supplied version.
  side_effects:
  - Advance the version and audit the action; maintain the publication timestamp and append an updated event with
    no changed property keys.
  who: Records Administrator (platform.custom-records.publish)
  provenance: observed
  source: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:publishRecord
- from: pending_review
  to: pending_review
  trigger: An administrator selects pending review for the record.
  guard: The parent enables publication and is active; the record is unarchived, unlocked for updates and at the
    supplied version.
  side_effects:
  - Advance the version and audit the action; maintain the publication timestamp and append no business event.
  who: Records Administrator (platform.custom-records.publish)
  provenance: observed
  source: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:publishRecord
- from: pending_review
  to: unpublished
  trigger: An administrator selects unpublished for the record.
  guard: The parent enables publication and is active; the record is unarchived, unlocked for updates and at the
    supplied version.
  side_effects:
  - Advance the version and audit the action; maintain the publication timestamp and append an updated event with
    no changed property keys.
  who: Records Administrator (platform.custom-records.publish)
  provenance: observed
  source: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:publishRecord
- from: published
  to: published
  trigger: An administrator selects published for the record.
  guard: The parent enables publication and is active; the record is unarchived, unlocked for updates and at the
    supplied version.
  side_effects:
  - Advance the version and audit the action; maintain the publication timestamp and append no business event.
  who: Records Administrator (platform.custom-records.publish)
  provenance: observed
  source: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:publishRecord
- from: unpublished
  to: draft
  trigger: An administrator selects draft for the record.
  guard: The parent enables publication and is active; the record is unarchived, unlocked for updates and at the
    supplied version.
  side_effects:
  - Advance the version and audit the action; maintain the publication timestamp and append an updated event with
    no changed property keys.
  who: Records Administrator (platform.custom-records.publish)
  provenance: observed
  source: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:publishRecord
- from: unpublished
  to: pending_review
  trigger: An administrator selects pending review for the record.
  guard: The parent enables publication and is active; the record is unarchived, unlocked for updates and at the
    supplied version.
  side_effects:
  - Advance the version and audit the action; maintain the publication timestamp and append an updated event with
    no changed property keys.
  who: Records Administrator (platform.custom-records.publish)
  provenance: observed
  source: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:publishRecord
- from: unpublished
  to: unpublished
  trigger: An administrator selects unpublished for the record.
  guard: The parent enables publication and is active; the record is unarchived, unlocked for updates and at the
    supplied version.
  side_effects:
  - Advance the version and audit the action; maintain the publication timestamp and append no business event.
  who: Records Administrator (platform.custom-records.publish)
  provenance: observed
  source: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:publishRecord
invalid:
- from: unpublishable
  to: published
  why: Publication requires a publishable object, and disabling that setting is blocked while records remain published.
- from: published
  to: unpublishable
  why: Publication requires a publishable object, and disabling that setting is blocked while records remain published.
concurrency: Publication locks and versions the record. Selecting its current state still updates system facts and
  audit, but emits no event and changes no business-value revision. Object replacement checks published records
  before disabling publication.
invariants:
- INV-DOM-PFM-MTD-005-05
- INV-DOM-PFM-MTD-004-05
evidence:
- 'services-platform at ad3f6a65: modules/custom-objects/services/persistence/custom-object-records.ts:publishRecord;
  record-events.ts; db/custom-object-records.table.ts (publication and published-at checks); docs/custom-objects.md
  §14; docs/business-events.md'
---

# Custom record publication

## The Lifecycle

```mermaid
stateDiagram-v2
  [*] --> unpublishable
  [*] --> draft
  draft --> published: select state
  pending_review --> published: select state
  unpublished --> published: select state
  published --> unpublished: select state
  published --> draft: select state
  published --> pending_review: select state
  draft --> pending_review: select state
  pending_review --> draft: select state
  draft --> draft: select state
  draft --> unpublished: select state
  pending_review --> pending_review: select state
  pending_review --> unpublished: select state
  published --> published: select state
  unpublished --> draft: select state
  unpublished --> pending_review: select state
  unpublished --> unpublished: select state
```

## Transitions Explained

Publication is independent of retention. The action accepts every pair of the four publication states, including selecting the current state. Entering publication sets its timestamp, leaving clears it, and unchanged state selection is accepted without a business event.

## What Cannot Happen

Publication requires a publishable object, and disabling that setting is blocked while records remain published.

## Concurrency and Timing

Publication locks and versions the record. Selecting its current state still updates system facts and audit, but emits no event and changes no business-value revision. Object replacement checks published records before disabling publication.
