# Journey: Memory review, edit, pause, and forget

This journey separates the four persistence levels currently present on
`/profile/memory`: BFF-hydrated Iris records, a server-authoritative pause and
single-record delete, browser-local edits and audit projections, and a
browser-local seven-day full-clear request. The UI exposes all four in one
surface, so the distinction is essential to an honest walkthrough.

## Personas

- **Routine signed-in customer** — reviews what Iris remembers, corrects a
  displayed fact, and pauses future durable writes.
- **Privacy-conscious customer** — deletes one synced memory and needs to know
  which controls are server-backed versus local simulations.
- **Multi-device customer** — expects the server-backed pause to follow the
  account to another browser context.

## Pre-conditions

- The customer is signed in; anonymous `/profile/memory` visits are redirected
  to `/welcome?redirect=/profile/memory`.
- `ProfileMemoryControls` can hydrate from
  `GET /v1/iris/adapter/review?role=settings` and read pause state from the Iris
  adapter.
- `oshun-profile-memory-controls-v1` may contain a cached local projection. The
  production initial state is empty; hydration or an existing cache supplies
  rows. An unavailable read can leave cached content visible with explicit
  status copy, while an empty response is interpreted alongside that local
  projection and the pause response.
- The phrase `iris-step-up` is a client challenge used by this component. It is
  not a primary-credential or server-issued step-up token.

## Steps

### 1. Open and identify the data source

- Open `/profile/memory` and wait for the Iris hydration status.
- A successful non-empty review shows server-derived facts. An empty review
  shows the explicit no-records state when no cached seed is present.
- If the review request fails, `data-profile-memory-bff-status` keeps cached
  controls readable and offers a retry. Cached rows are not evidence that the
  BFF currently holds those facts.

### 2. Review and filter the projection

- Category and scope chips filter the local view model.
- Selecting a fact opens its body, origin, provenance chain, recall history,
  downstream reference count, and audit-chain link.
- These fields are a browser projection of the currently hydrated control state;
  the detail pane performs no additional authoritative read.

### 3. Edit a displayed fact

- Change the label and content, then submit.
- `detectIrisUserMemoryEditConflict` compares the expected revision count with
  the browser state. A clean edit calls `editIrisUserMemoryFact`, supersedes the
  selected item, and creates a child revision with `editedFromItemId`.
- The edit is persisted to localStorage and browser telemetry only. There is no
  BFF edit request in `handleEditSubmit`, even when the original fact came from
  Iris.

### 4. Resolve a same-origin edit conflict

- A second tab can update the same localStorage record while the first tab holds
  a stale draft.
- **Keep remote version** selects the replacement already visible in browser
  state and rebases the editor.
- **Save my edit as the next revision** creates another local revision on top of
  that replacement.
- This is a same-origin browser conflict model, not a server or cross-device
  compare-and-swap contract.

### 5. Pause durable memory writes

- Toggle off-the-record mode.
- For a signed-in customer, the component sends
  `PATCH /v1/iris/adapter/pause?role=settings` and commits the returned pause
  only when that request succeeds.
- Iris continuity reports `indicator: "off"`; live remember attempts return
  `409 iris_memory_paused`; the assistant dock exposes memory scope `off`.
- Resume from the banner or header toggle to persist `paused: false` through the
  same route.

### 6. Verify the pause from another browser context

- Open a second isolated context with the same BFF identity.
- Its profile and assistant dock read the server pause as `off`.
- Resume on the first context, reload the second, and verify the assistant
  returns to session memory.
- This proves account-scoped pause propagation through the shared BFF; it does
  not prove real-time push between already-open devices.

### 7. Forget one synced fact

- Select a fact, type the component challenge, and choose permanent delete.
- For a fact from a successful Iris hydration, the component first calls
  `DELETE /v1/iris/adapter/memory/:memoryId?role=settings&mode=hard`.
- A successful response is mirrored into the local reducer as a tombstone;
  subsequent Iris review excludes the deleted id and content.
- The browser challenge gates the button path, but the delete route itself does
  not receive or validate that local challenge as server-issued step-up proof.

### 8. Request and cancel a full clear

- Type `FORGET EVERYTHING` and the local step-up phrase.
- `requestIrisUserMemoryFullClear` records a seven-day grace object inside the
  local control state; the component persists it to localStorage and shows the
  grace banner.
- Cancel clear updates that same local record and emits browser telemetry.
- No BFF request, server job, or durable account-wide schedule is created by
  these controls.

### 9. Export the visible memory state

- When the page has a synced Iris record, export first requests
  `/v1/iris/adapter/export?role=settings` and shows the non-secret server
  receipt.
- The downloadable signed bundle is still composed from the browser control
  state and includes its local audit chain.
- A local-only export must not be described as a server DSAR receipt.

## Post-conditions

- A successful pause/resume round trip is reflected by the server-authoritative
  Iris pause state and assistant memory-scope marker.
- A successfully deleted synced fact is absent from the next Iris review.
- Edits, conflict resolutions, tombstone mirrors, and the full-clear grace
  object remain in the browser control state.
- No server-authoritative full-memory-clear job exists from this journey.
- Browser telemetry contains metadata such as category, scope, revision, and
  outcome, but not raw edited memory content.

## Failure modes

- **Anonymous access** — redirects before the memory surface mounts.
- **Iris review unavailable** — cached rows remain visible with an unavailable
  banner; they must not be presented as fresh server state.
- **Offline pause** — the signed-in mutation fails closed, the toggle returns to
  false, and no pause banner appears.
- **Wrong local challenge** — the component performs no delete or full-clear
  mutation.
- **BFF delete fails** — the local tombstone is not committed for a synced fact.
- **Tenant-to-consumer scope promotion** — the local scope reducer rejects it
  and preserves the tenant badge.
- **Full-clear grace expires** — nothing executes automatically in this
  component; server cron execution is not wired to the local record.
- **Two real devices edit the same fact** — the localStorage conflict model
  cannot reconcile them.

## E2E coverage

- [`apps/oshun/web/e2e/profile-memory-controls.spec.ts`](../../apps/oshun/web/e2e/profile-memory-controls.spec.ts)
  covers local edit, export, tombstone, full-clear request/cancel, pause banner,
  telemetry redaction, and localStorage behavior.
- [`apps/oshun/web/e2e/memory-edit-pause-forget.spec.ts`](../../apps/oshun/web/e2e/memory-edit-pause-forget.spec.ts)
  covers same-origin conflict resolution; real Iris hydrate/export/delete;
  server-authoritative pause, blocked remember, review read-back, assistant
  marker, two-context propagation; route gating; offline pause failure; retry;
  and tenant-scope rejection.
- The scheduled full-clear execution remains deliberately uncovered because no
  server schedule is created by the page.

## Per-view files touched

- [`customer/09-account/profile-memory.md`](../customer/09-account/profile-memory.md)
  — primary controls.
- [`customer/09-account/profile.md`](../customer/09-account/profile.md) — entry
  route and assistant-dock read-back.

## Cross-references

- `apps/oshun/web/src/app/profile/memory/ProfileMemoryControls.tsx` — component
  persistence and BFF boundaries.
- `libs/oshun/memory-iris/src/user-memory-controls.ts` — local control reducers,
  audit chain, and grace-window model.
- [`account-deletion-and-dsar.md`](./account-deletion-and-dsar.md) — separate
  BFF data-rights request lifecycle.
- [`crisis-aware-tone-policy.md`](./crisis-aware-tone-policy.md) — crisis
  suppression boundaries.

## Open questions

- [ ] Add a server edit contract with revision preconditions and cross-device
      conflict semantics.
- [ ] Replace the static browser phrase with a genuine server-issued step-up
      proof for destructive operations.
- [ ] Connect request/cancel full clear to an account-scoped durable job,
      scheduled execution, and receipt.
- [ ] Define whether an empty authoritative Iris review should discard all
      cached seed rows rather than leave them visible.
- [ ] Add the promised multi-actor “forget all mentions” surface.
