---
id: WF-PFM-MTD-007
title: Delete a custom record under its relationship rules
trigger: Permanent removal follows every relationship policy inside one transaction.
product_area: platform
module: metadata
revision: 1
status: draft
design_intent: confirmed
origin: 'PLAT-M5 B1 (Andrew, 2026-10-19: dependants first) and B5 (rule applies anyway), CRM-M1 owner delete (services-platform:docs/milestones/PLAT-M5-custom-records.md#Decisions);
  PLAT-M6 D2 and assumption A2, plan approved 2026-10-21; services-platform:docs/assets.md §7 (Andrew, 2026-10-08:
  deleted records'' files are retired)'
implementation_evidence: observed
inference: []
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
implements:
- CAP-PFM-MTD-013
- CAP-PFM-MTD-019
- CAP-PFM-MTD-015
- CAP-PFM-MTD-014
moves:
- STATE-PFM-MTD-005
- STATE-PFM-MTD-010
- STATE-PFM-MTD-007
- STATE-PFM-MTD-008
crosses:
- SVC-PFM-MTD-custom-objects
- SVC-PFM-MTD-associations
idempotency: Repeated successful deletion returns not found. The parent and record locks, version check, reached-record
  locks and visited set bound a transactional cascade.
concurrency: Repeated successful deletion returns not found. The parent and record locks, version check, reached-record
  locks and visited set bound a transactional cascade.
hops:
- n: 1
  actor_or_service: Console record page
  action: The record page confirms permanent deletion and sends the current record version.
  anchor: react-console:components/console/custom-objects/record-action-panels.tsx
  seam: sync
  on_failure: Keep a refusal in the dialog and explain restricting connections.
  left_inconsistent: The record remains until deletion commits.
  observer: The initiating person or service and its operation logs.
  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 it'
- n: 2
  actor_or_service: Custom record store
  action: The store holds the active parent and record, validates the read version, lock, cascade depth and registered
    deletion checks.
  anchor: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:deleteRecord
  seam: sync
  on_failure: Stop on missing record, stale version, lock or an external check refusal.
  left_inconsistent: No deletion effects commit on refusal.
  observer: The initiating person or service and its operation logs.
  provenance: observed
  source: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:deleteWithRules
- n: 3
  actor_or_service: Relationship deletion rules (database function)
  action: Database policy locks endpoint links, removes detach or cascade links, returns cascade targets and rejects
    in-force restrictions.
  anchor: services-platform:modules/associations/services/persistence/associations.ts:applyEndpointDeletion
  seam: sync
  on_failure: Raise a conflict identifying restricting types and roll back the deleting transaction.
  left_inconsistent: All prior link changes in that transaction are undone.
  observer: The initiating person or service and its operation logs.
  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 res
- n: 4
  actor_or_service: Custom record store
  action: The store detaches files, recursively removes custom dependants under the same policies and appends deletion
    facts after dependants.
  anchor: services-platform:modules/custom-objects/services/persistence/custom-object-records.ts:deleteWithRules
  seam: sync
  on_failure: Any reached member’s refusal aborts the entire transaction.
  left_inconsistent: No record or dependant is partially removed.
  observer: The initiating person or service and its operation logs.
  provenance: test
  source: services-platform:modules/custom-objects/tests/integration/services/persistence/custom-object-records.integration.spec.js#writes
    every dependant’s event before
- n: 5
  actor_or_service: Database history capture
  action: At commit, history capture writes revisions for removed record values and connections.
  anchor: services-platform:modules/custom-objects/db/custom-object-record-change-events.table.ts
  seam: sync
  on_failure: Missing attribution rejects commit and restores all deletion effects.
  left_inconsistent: No deletion commits without its captured history.
  observer: The initiating person or service and its operation logs.
  provenance: documented
  source: services-platform:docs/custom-objects.md#24. History
- n: 6
  actor_or_service: Custom record store
  action: The committed deletion nudges event dispatch and leaves detached files awaiting disposal.
  anchor: services-platform:lib/events/platform-business-events.ts:nudgeBusinessEventsAfterCommit
  seam: event
  on_failure: A missed nudge waits for a later successful dispatcher schedule.
  left_inconsistent: Permanent file copies remain indefinitely under the absent cleanup binding.
  observer: Event delivery monitoring and the retained ledger.
  provenance: documented
  source: services-platform:docs/debt/custom-object-asset-cleanup.md
branches:
- Direct deletion accepts an archived record only under an active parent; inactive-parent removal is available through
  cascade policy.
waits: []
evidence:
- 'services-platform at ad3f6a65: modules/custom-objects/services/persistence/custom-object-records.ts (deleteRecord,
  deleteWithRules, inEventOrder); modules/associations/services/persistence/associations.ts:applyEndpointDeletion;
  docs/associations.md §6; docs/custom-objects.md §15; docs/debt/custom-object-asset-cleanup.md'
- 'react-console at baf6dae3: components/console/custom-objects/record-action-panels.tsx; lib/custom-objects/related.ts'
controls: [TC-AVL-004, TC-AVL-005, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-004, TC-IAM-001, TC-IAM-002, TC-IAM-004, TC-IAM-005, TC-IAM-006, TC-LOG-001, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-MON-001, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-004, TC-PI-005, TC-PRV-001, TC-PRV-002, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-TEN-004, TC-VEN-001, TC-VEN-002, TC-VEN-003]
---

# Delete a custom record under its relationship rules

## What It Does

Permanent removal follows every relationship policy inside one transaction. Custom dependants are removed first, and any refusing member stops the complete deletion.

## The Flow

```mermaid
sequenceDiagram
  participant Admin as Records administrator
  participant Store as Record store
  participant Rules as Deletion rules (database)
  participant Hist as History capture
  Admin->>Store: delete (version)
  Store->>Store: lock, version, lock flag, depth
  Store->>Rules: apply link rules for the record
  alt restrict link in force
    Rules-->>Store: refuse
    Store-->>Admin: refused, nothing removed
  else
    Rules-->>Store: removed links, cascade targets
    loop each cascade target, depth up to ten
      Store->>Rules: apply its rules
    end
    Store->>Store: detach files, delete, audit, events (dependants first)
    Store->>Hist: deletion revisions at commit
    Store-->>Admin: deleted with the cascaded records listed
  end
```

## When Something Fails

Keep a refusal in the dialog and explain restricting connections. The record remains until deletion commits. Raise a conflict identifying restricting types and roll back the deleting transaction. All prior link changes in that transaction are undone. A missed nudge waits for a later successful dispatcher schedule. Permanent file copies remain indefinitely under the absent cleanup binding.

## Open Design Questions

File cleanup and the unused external deletion-check integration remain recorded gaps.
