V1 Web PWA · Journey

Journey: Memory review, edit, pause, and forget

A source-reconciled journey record for V1 Web PWA — shipped behavior, state boundaries, failure modes, and the automation evidence available today.

automated · 2 specs verdict: partial· 2026-05-29
9sections6 minread

On this page
Journey at a glance
ActorsRoutine signed-in customerPrivacy-conscious customerMulti-device customer
Automation2 E2E spec(s) · verdict: partial· 2026-05-29

Journey flow#

Generated from the authored steps below — click a node to jump to that section.

flowchart TD s1["1. Open and identify the data source"] s2["2. Review and filter the projection"] s3["3. Edit a displayed fact"] s4["4. Resolve a same-origin edit conflict"] s5["5. Pause durable memory writes"] s6["6. Verify the pause from another browser cont…"] s7["7. Forget one synced fact"] s8["8. Request and cancel a full clear"] s9["9. Export the visible memory state"] s1 --> s2 --> s3 --> s4 --> s5 --> s6 --> s7 --> s8 --> s9 click s1 href "#1-open-and-identify-the-data-source" click s2 href "#2-review-and-filter-the-projection" click s3 href "#3-edit-a-displayed-fact" click s4 href "#4-resolve-a-same-origin-edit-conflict" click s5 href "#5-pause-durable-memory-writes" click s6 href "#6-verify-the-pause-from-another-browser-context" click s7 href "#7-forget-one-synced-fact" click s8 href "#8-request-and-cancel-a-full-clear" click s9 href "#9-export-the-visible-memory-state" s9 --> v(["verdict: partial"]) click v href "../results/memory-edit-pause-forget.html" style v stroke:#d6a531,color:#d6a531

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 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 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#

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 — separate BFF data-rights request lifecycle.
  • 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.