---
id: CAP-PFM-MTD-013
title: Retire or Publish Custom Records
feature: FEAT-PFM-MTD-05
product_area: platform
module: metadata
revision: 1
status: draft
product_intent: confirmed
implementation_evidence: observed
supersedes:
  - CAP-CO-REC-006
  - CAP-CO-REC-007
  - CAP-CO-REC-008
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - >-
    services-platform:docs/proposals/custom-objects/09-decisions.md#D-19 (Andrew, 2026-10-18: archive under
    the delete key)
  - 'services-platform:docs/milestones/PLAT-M5-custom-records.md#PLAT-M5 B1, B5, D3'
  - >-
    services-platform:docs/milestones/PLAT-M6-custom-record-relationships.md#Changes requested (2026-10-21,
    "All or nothing")
  - 'services-platform:docs/milestones/plans/PLAT-M5-plan.md#PLAT-M5-S07'
purpose: >-
  Records administrators need deliberate lifecycle actions for custom records. Publication, archival and
  deletion serve different staff outcomes.
outcomes:
  - Records administrators need deliberate lifecycle actions for custom records.
  - Cascades can reach dependent custom records and roll back if a safeguard refuses any member.
actors:
  - ACT-PFM-010
  - ACT-PFM-012
surfaces:
  - console
  - api
preconditions:
  - The owning custom object is active.
postconditions:
  - 'Lifecycle actions leave audits, and deletion removes owned values and links while detaching assets.'
permissions:
  - key: platform.custom-records.publish
    where_checked: api
    scope: record
  - key: platform.custom-records.delete
    where_checked: api
    scope: record
rules:
  - id: BR-CAP-PFM-MTD-013-01
    proved_by: [ATS-PFM-MTD-013-01, ATS-PFM-MTD-013-11, TST-PFM-MTD-065]
    statement: >-
      Publishable records begin in draft and accept draft, pending-review, published or unpublished states;
      entering publication sets its time, leaving it clears the time and nonpublishable objects reject
      publication.
    kind: lifecycle
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/custom-objects/tests/integration/services/persistence/custom-object-records.integration.spec.js#refuses
      publication on an object that is not publishable
    origin: none
  - id: BR-CAP-PFM-MTD-013-02
    proved_by: [ATS-PFM-MTD-013-02, TST-PFM-MTD-065]
    statement: >-
      Record archival retains values, files and links while excluding ordinary-list entries and refusing
      edits, publication and repeated archival until restoration; deletion remains available for an active
      object.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/custom-objects/tests/integration/services/persistence/custom-object-records.integration.spec.js#archives
      a record with everything kept
    origin: 'services-platform:docs/proposals/custom-objects/09-decisions.md#D-19'
  - id: BR-CAP-PFM-MTD-013-03
    proved_by: [ATS-PFM-MTD-013-03, TST-PFM-MTD-065]
    statement: >-
      Permanent deletion requires the current version, removes record and owned value reservations and
      detaches files for retirement.
    kind: lifecycle
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/custom-objects/tests/integration/services/persistence/custom-object-records.integration.spec.js#deletes
      a record with its values and unique values
    origin: none
  - id: BR-CAP-PFM-MTD-013-04
    proved_by: [ATS-PFM-MTD-013-04, TST-PFM-MTD-037, TST-PFM-MTD-065]
    statement: >-
      A restricting link in force prevents deletion without removing anything, including a link whose end date
      is still current or future.
    kind: validation
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/custom-objects/tests/integration/services/persistence/custom-object-records.integration.spec.js#refuses
      to delete a record an open restricting association names, and removes nothing
    origin: >-
      services-platform:docs/milestones/plans/PLAT-M6-plan.md#5. D2 (Andrew, 2026-10-21: in force until it
      ends)
  - id: BR-CAP-PFM-MTD-013-05
    proved_by: [ATS-PFM-MTD-013-05, ATS-PFM-MTD-013-10, TST-PFM-MTD-022, TST-PFM-MTD-037, TST-PFM-MTD-065]
    statement: >-
      Cascading deletion follows linked custom records through the same safeguards to a maximum depth of ten
      and rolls back the entire deletion when any member is refused.
    kind: invariant
    enforced_at:
      - service
      - database
      - console
    must_prove: true
    provenance: test
    source: >-
      react-console:acceptance/custom-objects/playwright/journeys/PLAT-M6-S08.spec.ts#PLAT-M6-S08: an insured
      boat cannot be deleted and a builder's deletion takes its boats except the refused one
    origin: >-
      services-platform:docs/milestones/PLAT-M6-custom-record-relationships.md#Changes requested (Andrew,
      2026-10-21: "All or nothing")
  - id: BR-CAP-PFM-MTD-013-06
    proved_by: [ATS-PFM-MTD-013-06, ATS-PFM-MTD-015-08, ATS-PFM-MTD-019-10, TST-PFM-MTD-065]
    statement: >-
      Deletion announcements order link removals first, cascaded records from deepest to shallowest next and
      the originating record last.
    kind: policy
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/custom-objects/tests/integration/services/persistence/custom-object-records.integration.spec.js#writes
      every dependant’s event before the record it depended on: the associations, then the cascade deepest
      first (B1)
    origin: >-
      services-platform:docs/milestones/PLAT-M5-custom-records.md#PLAT-M5 B1 (Andrew, 2026-10-19: "Dependants
      first")
  - id: BR-CAP-PFM-MTD-013-07
    proved_by: [ATS-PFM-MTD-013-07, TST-PFM-MTD-065]
    statement: >-
      Owner cascades still delete records of archived or draft objects even though direct deletion from those
      objects is refused.
    kind: policy
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/custom-objects/tests/integration/services/persistence/custom-object-records.integration.spec.js#applies
      the owner’s cascade to a record of an archived custom object (B5: the rule applies whatever the type’s
      state)
    origin: >-
      services-platform:docs/milestones/PLAT-M5-custom-records.md#PLAT-M5 B5 (Andrew, 2026-10-19: "Rule
      applies anyway")
  - id: BR-CAP-PFM-MTD-013-08
    proved_by: [ATS-PFM-MTD-013-08, TST-PFM-MTD-065]
    statement: >-
      Publication, archival, restoration and deletion record audit events in their transaction, including the
      chosen publication state.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/custom-objects/tests/integration/services/persistence/custom-object-records.integration.spec.js#records
      the publication and its state in the audit events
    origin: none
  - id: BR-CAP-PFM-MTD-013-09
    proved_by: [ATS-PFM-MTD-013-09, TST-PFM-MTD-007, TST-PFM-MTD-022]
    statement: >-
      Authorized record-page actions offer publication, unpublication, archival, restoration and confirmed
      deletion, explaining restricting links in a refused deletion confirmation.
    kind: policy
    enforced_at:
      - console
    must_prove: true
    provenance: test
    source: >-
      react-console:acceptance/custom-objects/playwright/journeys/PLAT-M5-S07.spec.ts#PLAT-M5-S07: publish,
      archive and restore from the boat page; History names each revision and who made it
    origin: 'services-platform:docs/milestones/plans/PLAT-M5-plan.md#PLAT-M5-S07'
  - id: BR-CAP-PFM-MTD-013-10
    proved_by: []
    statement: >-
      Direct store deletion consults an optional external deletion check, but no integration registers it and
      cross-service deletion does not consult it.
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: documented
    source: >-
      services-platform:docs/associations.md#The contract for another service (CRM's contact and organization
      deletes)
    origin: none
scenarios:
  - id: SC-CAP-PFM-MTD-013-01
    given: A records administrator opens the first boat record.
    when: 'Publish it, archive it and restore it.'
    then: The actions succeed and History identifies their revisions and authors.
    provenance: test
    source: >-
      react-console:acceptance/custom-objects/playwright/journeys/PLAT-M5-S07.spec.ts#PLAT-M5-S07: publish,
      archive and restore from the boat page; History names each revision and who made it
edge_cases:
  - id: SC-CAP-PFM-MTD-013-02
    given: A builder cascades to boats and one boat has restricting insurance.
    when: 'Try deleting the builder, then repeat after the insurance ends.'
    then: >-
      The protected deletion removes nothing; after the protection ends, the builder and its dependent boats
      are removed.
    provenance: documented
    source: 'services-platform:docs/milestones/plans/PLAT-M6-plan.md#PLAT-M6-S08'
constraints: []
depends_on:
  - CAP-PFM-MTD-012
  - CAP-PFM-MTD-019
related:
  - CAP-PFM-MTD-011
  - CAP-PFM-MTD-015
journeys:
  - JNY-PFM-MTD-002
  - JNY-PFM-MTD-005
open_questions: []
concepts:
  - CON-PFM-MTD-005
evidence:
  - >-
    services-platform at ad3f6a6582843008ed0f5a17b131878d15829af1:
    modules/custom-objects/aws/api/custom-object-records.routes.ts ,
    services/persistence/custom-object-records.ts ; tests
    integration/services/persistence/custom-object-records.integration.spec.js ,
    e2e/custom-object-records.e2e.spec.js; docs/custom-objects.md §14 to §16.
  - >-
    react-console at baf6dae382d6f41dce976c7f848667ccc37e076f:
    components/console/custom-objects/record-action-panels.tsx; Playwright PLAT-M5-S07, PLAT-M6-S08.
controls: [TC-AVL-005, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-DAT-001, TC-DAT-003, TC-DAT-004, TC-LOG-001, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-PI-001, TC-PI-003, TC-PI-005, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-TEN-004, TC-VEN-001, TC-VEN-002, TC-VEN-003]
exercised_by: [FAS-PFM-MTD-05-02, FAS-PFM-MTD-05-03, FAS-PFM-MTD-05-04]
suites: [TST-PFM-MTD-007, TST-PFM-MTD-022, TST-PFM-MTD-037, TST-PFM-MTD-065]
---

# Retire or Publish Custom Records

## Purpose

Records administrators need deliberate lifecycle actions for custom records. Publication, archival and deletion serve different staff outcomes.

## How It Works

An authorized administrator chooses an action on the record. Publication changes its public standing when the object permits publication. Archive removes a record from normal browsing while preserving information. Restore makes that record available again. Delete permanently removes the record after its version and relationship checks. Cascades can reach dependent custom records and roll back if a safeguard refuses any member. Each action records its audit, history and applicable event effects for later review.

## Relationships

Access grants lifecycle permissions. Relationship policy governs deletion effects, and history explains the committed changes.
