V1 Web PWA · Walk result

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

A dated evidence record for V1 Web PWA: observed behavior, current source reconciliation, automation evidence, and explicit proof limits.

verdict: partial· 2026-05-29
8sections8 minread1table

On this page
  • Walked: 2026-05-29 against bf12b0f7d8c291499e1df1ec75d4bd21acf3f6b1. The retained /tmp walker is ephemeral, so this is a dated smoke record rather than a reproducible run artifact. The client-bundle fix later landed in adae8117ddb084fd6dbf9c26b0a31e4f86da2148; the historical /v1/memory stub landed in 03d45f0ad7a276369d9536f8f15e7ba0c627d945.
  • Reconciled: 2026-07-18 against the current profile component, browser reducers, Iris BFF route and durable adapter, startup wiring, and both named Playwright specs. This was source review, not a fresh application run.
  • Verdict: partial / deep for the server-backed core — the current suites deeply cover Iris hydration, server-authoritative pause, blocked and resumed writes, single-record deletion, and an export receipt. Editing, conflict resolution, the audit projection, and the seven-day full-clear request remain browser-local; the destructive challenge is not server-issued.
  • Current authority: WALKTHROUGH/journeys/memory-edit-pause-forget.md preserves those authority boundaries step by step.

Result at a glance#

Interaction Proof · limit
Iris hydrate/review Authority / proof: GET /v1/iris/adapter/review?role=settings&pageSize=100 supplies server records; browser state and oshun-profile-memory-controls-v1 cache the projection. Real-BFF cases cover hydrate, empty, unavailable/retry, consent, filters, detail, and tenant scope. Limit: an unavailable read may leave cached rows visible; detail and filtering do not perform a fresh authoritative read.
Edit/conflict Authority / proof: local reducers create revisions; tests cover edit, audit projection, telemetry redaction, and two-tab keep-remote/overwrite. Limit: no BFF edit, durable revision precondition, or cross-device compare-and-swap.
Pause/resume Authority / proof: signed-in controls call PATCH /v1/iris/adapter/pause?role=settings; durable Iris persists the opt-out. Tests prove continuity off, 409 iris_memory_paused, two contexts, resume, and a later write. Limit: the second context proves read-back after reload, not real-time push to open devices.
Single-fact delete Authority / proof: a synced row sends settings role, hard mode, reason, and confirmed=true; durable Iris tombstones the id. Tests prove the real delete, local mirror, and next-review absence. Limit: the phrase is static, and the route defaults missing confirmed to true instead of validating server-issued step-up.
Full clear Authority / proof: request/cancel mutate browser state, localStorage, and telemetry; tests cover the challenge, seven-day banner, and cancellation. Limit: no BFF request, durable account-wide schedule, executor, or completion receipt.
Export Authority / proof: POST /v1/iris/adapter/export?role=settings returns receipt metadata; the browser separately composes the bundle. Tests cover id/count/checksum plus the local artifact and audit chain. Limit: the receipt does not make the downloaded artifact a server-owned DSAR export.

Evidence map#

Solid edges show the customer-facing sequence exercised across the named specs. Dashed edges name the production authority the current surface does not yet provide. Only pause/resume and deletion in this sequence mutate durable Iris authority; edit/conflict and full clear remain local projections.

flowchart TB A[Signed-in profile] --> B[Hydrate Iris review, consent, and pause] B --> C[Browser control projection and local cache] C --> D[Edit and resolve same-origin conflict] D --> E[Pause or resume durable writes] E --> F[Delete one synced fact] F --> G[Request seven-day full clear] G --> H[Export receipt and browser bundle] D -. missing .-> I[Server edit and revision CAS] F -. missing .-> J[Server-issued destructive step-up] G -. missing .-> K[Durable account-wide clear job] H -. not delivered .-> L[Server-owned export artifact]

Proven observations#

Hydration clearly separates current Iris state from a cached projection#

  • ProfileMemoryControls starts from an honestly empty production state, then requests Iris review, consent, and pause data. A successful non-empty review maps server records into the control projection; the component does not ship fabricated customer memories as initial facts.
  • The browser persists its projection under the exact key oshun-profile-memory-controls-v1. When review is unavailable, retained cached rows remain readable beside an explicit unavailable state and retry. When Iris returns no records, the rendered outcome still depends on the local projection and pause response rather than proving that every cached row was authoritatively erased.
  • Category and scope chips, fact detail, provenance, recall history, downstream counts, and the local audit-chain link operate on the hydrated browser model. They are useful inspection affordances, but selecting a row does not issue a second server read.

Edit and conflict resolution are deliberately browser-local#

  • handleEditSubmit compares the editor's expected revision against browser state, calls the local edit reducer, writes the next projection to localStorage, and emits redacted browser telemetry. It does not send a BFF edit request even when the selected row originated in Iris.
  • The edit reducer supersedes the displayed item and creates a child revision with editedFromItemId. The resulting audit chain describes operations in this browser model; it is not a durable server ledger for the Iris record.
  • The component listens for the same storage key's storage event. Two tabs on one origin can therefore expose a stale-draft conflict and choose the remote localStorage revision or layer another local revision on it. Two devices do not share that CAS boundary.

Pause and single-record deletion reach durable Iris authority#

  • Signed-in pause toggles call the Iris adapter and commit the returned state only after success. The offline case fails closed: the UI does not pretend a pause was accepted when the mutation failed.
  • The real-BFF suite proves the behavioral gate, not just the toggle. Continuity reports memory off; a live remember attempt returns 409 iris_memory_paused; the blocked sentence is absent from review; resume persists paused: false; and a later remember call creates a visible row.
  • Two isolated browser contexts with the same BFF identity read the same account-scoped pause after navigation/reload. That is durable read-back, not a claim of socket-driven synchronization between already-mounted pages.
  • Deleting a synced fact sends hard mode, a reason, and confirmed=true to the management route. The durable Iris adapter tombstones the id, and a later review hides it. Only after a successful response does the component mirror the deletion into its local reducer.

Full clear and export combine unlike authorities in one surface#

  • Typing FORGET EVERYTHING plus iris-step-up can create or cancel a seven-day grace object in browser state. The library tests the state machine, and the profile spec tests its banner and telemetry, but there is no matching Iris BFF full-clear route or scheduled worker consuming that record.
  • For synced state, export first posts to the Iris adapter and displays a non-secret receipt with id, count, and checksum metadata. The downloadable “signed” bundle is then assembled from the browser control projection by exportIrisUserMemoryBundle; the server does not return that artifact's bytes through this flow.
  • profile-memory-controls.spec.ts contains four local/stub-driven cases. memory-edit-pause-forget.spec.ts contains sixteen cases spanning anonymous gating, failure/retry, local conflicts, real Iris hydrate/export/delete, pause/read-back, two contexts, and the blocked-write boundary.

Boundaries and gaps#

  • Cached rows are not a fresh Iris read. Unavailable and retry states must stay visible whenever the page is showing retained browser data.
  • A local revision is not a server edit. The UI cannot promise that its revised content changed the durable Iris fact.
  • A same-origin conflict is not cross-device compare-and-swap. The storage event model coordinates tabs sharing one browser origin, not independent devices or BFF writers.
  • A static phrase is not server-issued step-up. iris-step-up never reaches the route as a credential, and confirmed currently defaults to true when absent at the server boundary.
  • A local grace record is not a deletion schedule. Nothing on this page registers, executes, or proves an account-wide full-memory clear.
  • A tombstone mirror is not a second deletion. The server tombstone is authoritative for a synced id; the local reducer updates the projection only after that mutation succeeds.
  • An export receipt is not the downloaded bundle. Server metadata and the browser-composed artifact have distinct provenance and assurance levels.
  • A memory export is not a DSAR lifecycle. The separate data-rights journey owns request, status, cancellation, and delivery claims.
  • Historical /v1/memory smoke is not current Iris proof. The present flow uses /v1/iris/adapter/*; the 2026-05-29 walker cannot substantiate later route behavior.
  • Source reconciliation is not execution. Neither cited application suite was rerun for this documentation audit.

Re-run evidence#

Run the two focused suites sequentially against one production-like web/BFF pair and one immutable commit:

bash
pnpm --dir apps/oshun/web exec playwright test -c playwright.config.ts e2e/profile-memory-controls.spec.ts --project=chromium --workers=1
pnpm --dir apps/oshun/web exec playwright test -c playwright.config.ts e2e/memory-edit-pause-forget.spec.ts --project=chromium --workers=1

Retain the commit, browser and BFF reports, backing-store tier, seeded identity, and before/after Iris snapshots. A stronger follow-up should also retain a restart result, two real-device traces, the server-issued step-up exchange, and a durable full-clear request through execution and receipt.

Source trail#

Cross-references#

Open questions#

  • Which server edit contract will accept revision preconditions and return a durable conflict that independent devices can resolve safely?
  • Which authentication flow will issue, expire, bind, and consume a genuine step-up credential for destructive memory operations?
  • Where will full-clear request, cancellation, grace expiry, execution, and completion receipt live as one durable account-scoped lifecycle?
  • Should an authoritative empty Iris review clear cached rows, quarantine them, or preserve them under an explicitly historical/offline label?
  • Will export return a server-owned artifact with durable retention and access controls, or remain separate from the account DSAR workflow?
  • When will “forget all mentions” across authorized actors gain a real UI, policy contract, and multi-record server operation?