---
id: STATE-COM-CAT-004
title: Managed catalog file lifecycle
object: DOM-COM-CAT-003
product_area: commerce
module: catalog
revision: 1
status: draft
design_intent: confirmed
implementation_evidence: partially-observed
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
states:
  - name: preparing
    meaning: The save has started copying an asset before opening its record transaction.
  - name: ready
    meaning: The copied file is available for attachment by the pending save.
  - name: attached
    meaning: A saved record retains the permanent asset reference.
  - name: detached
    meaning: A committed change or deletion has released the asset reference.
  - name: abandoned
    meaning: Preparation produced a file but the parent save did not commit.
  - name: discarding
    meaning: Cleanup has claimed the asset and submitted work to its queue.
  - name: discarded
    meaning: An unreferenced asset has been deleted or retired with thirty-day retention.
  - name: failed
    meaning: Cleanup exhausted its delivery attempts and retains a failure reason for operator review.
transitions:
  - from: preparing
    to: ready
    trigger: Asset copying finishes successfully.
    guard: The asset source must be readable by the pipeline.
    side_effects:
      - The pending record receives the prepared permanent asset reference.
    who: The saving request
    provenance: test
    source: >-
      services-commerce:modules/catalog/tests/e2e/product-categories.e2e.spec.js#answers 400 to a picture the
      pipeline cannot read as a file, creating nothing
  - from: ready
    to: attached
    trigger: The parent save commits the prepared reference.
    guard: The save must have prepared the reference it commits.
    side_effects: []
    who: The saving request
    provenance: test
    source: >-
      services-commerce:modules/catalog/tests/integration/services/persistence/product-listings.integration.spec.js#refuses
      a gallery picture written past the pipeline (a reference the save never prepared)
  - from: ready
    to: abandoned
    trigger: The parent save fails after copying.
    guard: No additional condition applies.
    side_effects: []
    who: The saving request
    provenance: documented
    source: 'services-commerce:modules/catalog/services/assets/catalog-assets.ts'
  - from: attached
    to: detached
    trigger: A saved change or removal releases the reference.
    guard: A retained unchanged picture bypasses detachment and keeps its existing reference.
    side_effects: []
    who: The saving or deleting request
    provenance: test
    source: >-
      services-commerce:modules/catalog/tests/integration/services/persistence/product-categories.integration.spec.js#deletes
      the category with its memberships and detaches its picture; a second delete is 404
  - from: detached
    to: discarding
    trigger: The scheduled sweep claims a due released file.
    guard: The cleanup due instant must have arrived.
    side_effects:
      - Cleanup publishes an individual work message for the file.
    who: Scheduled asset sweep
    provenance: documented
    source: 'services-commerce:modules/catalog/services/assets/clean-up-catalog-assets.ts'
  - from: abandoned
    to: discarding
    trigger: The scheduled sweep claims a due abandoned copy.
    guard: The cleanup due instant must have arrived.
    side_effects:
      - Cleanup publishes an individual work message for the file.
    who: Scheduled asset sweep
    provenance: documented
    source: 'services-commerce:modules/catalog/services/assets/clean-up-catalog-assets.ts'
  - from: discarding
    to: discarded
    trigger: Queue processing finishes cleanup.
    guard: The workspace-scoped owner check must find no retained reference.
    side_effects:
      - Released assets receive thirty-day retirement; uncommitted copies are deleted.
    who: Cleanup queue consumer
    provenance: documented
    source: 'services-commerce:modules/catalog/services/assets/clean-up-one-catalog-asset.ts'
  - from: discarding
    to: attached
    trigger: Settlement finds that a saved record still retains the reference.
    guard: A saved owner record must still name the asset.
    side_effects:
      - The referenced asset is retained.
    who: Cleanup queue consumer
    provenance: inferred
    source: 'services-commerce:modules/catalog/services/assets/clean-up-one-catalog-asset.ts'
  - from: discarding
    to: failed
    trigger: The final queue delivery cannot complete cleanup.
    guard: The receipt must be the final permitted retry after earlier failures.
    side_effects:
      - The failed row records the reason and the queue sends exhausted work for operator review.
    who: Cleanup queue consumer
    provenance: documented
    source: 'services-commerce:modules/catalog/aws/lambda/ASSET_CLEANUP_CONSUMER.ts'
invalid:
  - from: discarded
    to: attached
    why: A retired or deleted asset requires fresh preparation before another attachment.
  - from: preparing
    to: attached
    why: The parent transaction can attach only a successfully prepared reference.
concurrency: >-
  The sweep has reserved concurrency of one and the consumer mapping permits two concurrent invocations.
  Consumer settlement checks references again; individual failed messages retry up to five receives.
invariants:
  - INV-DOM-COM-CAT-003-05
  - INV-DOM-COM-CAT-002-06
evidence:
  - >-
    services-commerce at c8b66a98: modules/catalog/db/managed-assets.table.ts;
    services/assets/catalog-assets.ts, clean-up-catalog-assets.ts, clean-up-one-catalog-asset.ts;
    aws/logic/catalog-asset-cleanup.lambda.ts; aws/resources/catalog-asset-cleanup-queue.sqs.ts.
  - >-
    services-commerce at c8b66a98:
    modules/catalog/tests/integration/services/assets/catalog-assets.integration.spec.js.
---

# Managed catalog file lifecycle

## The Lifecycle

```mermaid
stateDiagram-v2
  [*] --> preparing: save submits a picture or file
  preparing --> ready: copied
  ready --> attached: record commits
  ready --> abandoned: record refused
  attached --> detached: replaced, removed or record deleted
  detached --> discarding: sweep claims
  abandoned --> discarding: sweep claims
  discarding --> discarded: consumer settles
  discarding --> attached: still referenced
  discarding --> failed: last delivery fails
  discarded --> [*]
```

## Transitions Explained

Preparing: The save has started copying an asset before opening its record transaction. Ready: The copied file is available for attachment by the pending save. Attached: A saved record retains the permanent asset reference. Detached: A committed change or deletion has released the asset reference. Abandoned: Preparation produced a file but the parent save did not commit. Discarding: Cleanup has claimed the asset and submitted work to its queue. Discarded: An unreferenced asset has been deleted or retired with thirty-day retention. Failed: Cleanup exhausted its delivery attempts and retains a failure reason for operator review.

## What Cannot Happen

A retired or deleted asset requires fresh preparation before another attachment. The parent transaction can attach only a successfully prepared reference.

## Concurrency and Timing

The sweep has reserved concurrency of one and the consumer mapping permits two concurrent invocations. Consumer settlement checks references again; individual failed messages retry up to five receives.
