---
id: STATE-PFM-NOT-004
title: Personal read and archive state
object: DOM-PFM-NOT-003
product_area: platform
module: notifications
revision: 1
status: draft
design_intent: confirmed
origin: 'PLAT-M23 plan approved by Andrew 2026-10-21 18:05 ET (scope: inbox, newest first, read and unread
  states, archive), services-platform:docs/milestones/plans/PLAT-M23-plan.humanized.md#2. Scope'
implementation_evidence: observed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
states:
- name: unread
  meaning: The notice is visible and contributes to unread counts while applicable.
- name: read
  meaning: The notice has a retained first-read time.
- name: archived unread
  meaning: The notice is hidden but has no read time.
- name: archived read
  meaning: The notice is hidden and retains its read time.
transitions:
- from: unread
  to: read
  trigger: The person opens a notice, marks it read, or invokes bulk reading.
  guard: The selected notice belongs to the authenticated person.
  side_effects:
  - Set the first-read time without replacing an existing one.
  - Remove it from unread counts.
  who: Staff notification recipient
  provenance: test
  source: services-platform:modules/notifications/tests/e2e/notifications.e2e.spec.js#marks one read and
    unread, archives and unarchives it, answering it each time
- from: read
  to: unread
  trigger: The person chooses to mark the notice unread.
  guard: Ownership must match the authenticated person.
  side_effects:
  - Remove its read time.
  who: Staff notification recipient
  provenance: test
  source: services-platform:modules/notifications/tests/e2e/notifications.e2e.spec.js#marks one read and
    unread, archives and unarchives it, answering it each time
- from: unread
  to: archived unread
  trigger: The person archives an unread notice.
  guard: Ownership must match the authenticated person.
  side_effects:
  - Hide it from the default inbox and unread count.
  who: Staff notification recipient
  provenance: test
  source: services-platform:modules/notifications/tests/e2e/notifications.e2e.spec.js#marks one read and
    unread, archives and unarchives it, answering it each time
- from: read
  to: archived read
  trigger: The person archives a read notice.
  guard: Ownership must match the authenticated person.
  side_effects: []
  who: Staff notification recipient
  provenance: test
  source: services-platform:modules/notifications/tests/e2e/notifications.e2e.spec.js#marks one read and
    unread, archives and unarchives it, answering it each time
- from: archived unread
  to: unread
  trigger: The person restores an unread archived notice.
  guard: Ownership must match the authenticated person.
  side_effects: []
  who: Staff notification recipient
  provenance: test
  source: services-platform:modules/notifications/tests/e2e/notifications.e2e.spec.js#marks one read and
    unread, archives and unarchives it, answering it each time
- from: archived read
  to: read
  trigger: The person restores a read archived notice.
  guard: Ownership must match the authenticated person.
  side_effects: []
  who: Staff notification recipient
  provenance: test
  source: services-platform:modules/notifications/tests/e2e/notifications.e2e.spec.js#marks one read and
    unread, archives and unarchives it, answering it each time
invalid:
- from: unread
  to: read
  why: Personal operations cannot select another person's notice.
- from: archived unread
  to: read
  why: Bulk reading excludes archived notices; individual reading can change their read state while retaining
    the archive.
concurrency: Personal updates select the caller-owned row. Bulk reading accepts category and creation-time
  boundaries and leaves later arrivals unread. Folding requires an unread, unarchived notice; subsequent
  occurrences create a new notice after reading.
invariants:
- INV-DOM-PFM-NOT-003-08
evidence:
- 'services-platform at ad3f6a65: modules/notifications/services/persistence/instances.ts (changeInstanceState,
  markAllRead, countUnread); aws/api/notifications.routes.ts (the me routes).'
---
# Personal read and archive state

## The Lifecycle

```mermaid
stateDiagram-v2
    state "unread" as s0
    state "read" as s1
    state "archived unread" as s2
    state "archived read" as s3
    s0 --> s1
    s1 --> s0
    s0 --> s2
    s1 --> s3
    s2 --> s0
    s3 --> s1
```

## Transitions Explained

The transition rows describe stored state changes, their checks and their recorded effects. A queue receive, provider outcome and staff action can reach different lifecycle boundaries.

## What Cannot Happen

Personal operations cannot select another person's notice. Bulk reading excludes archived notices; individual reading can change their read state while retaining the archive.

## Concurrency and Timing

Personal updates select the caller-owned row. Bulk reading accepts category and creation-time boundaries and leaves later arrivals unread. Folding requires an unread, unarchived notice; subsequent occurrences create a new notice after reading.
