V1 Web PWA · Journey

Journey: Arete weekly review (Sunday)

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

automated · 4 specs verdict: partial· 2026-05-29
9sections13 minread1table

On this page
Journey at a glance
ActorsSunday-reminder userSkipped-last-week userMulti-quiet-day userTenant-bound institutional userPower-user reviewer
Automation4 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. Sunday push or in-app reminder fires"] s2["2. Arrive on /arete/review"] s3["3. Walk Act I — Celebrate (look back)"] s4["4. Act II — Acknowledge / Notice"] s5["5. Act III — Choose / Pivot"] s6["6. Act IV — Invite / Commit"] s7["7. KPIs + journal lines (right column)"] s8["8. Continuity card and next-week plan"] s9["9. Return to /arete and verify continuity"] s1 --> s2 --> s3 --> s4 --> s5 --> s6 --> s7 --> s8 --> s9 click s1 href "#1-sunday-push-or-in-app-reminder-fires" click s2 href "#2-arrive-on-aretereview" click s3 href "#3-walk-act-i--celebrate-look-back" click s4 href "#4-act-ii--acknowledge--notice" click s5 href "#5-act-iii--choose--pivot" click s6 href "#6-act-iv--invite--commit" click s7 href "#7-kpis--journal-lines-right-column" click s8 href "#8-continuity-card-and-next-week-plan" click s9 href "#9-return-to-arete-and-verify-continuity" s9 --> v(["verdict: partial"]) click v href "../results/weekly-review-arete.html" style v stroke:#d6a531,color:#d6a531

Sunday's push or in-app reminder arrives, the user opens /arete/review, walks the four acts (look back / acknowledge / pivot / commit), checks the week's KPI tiles and journal lines, sees the continuity card, and commits a plan for the next week. Tests the cadence reminder, the four-act composition, the KPI/journal sidebar, and Lilith's recovery/streak tone policy.

Personas#

  • Sunday-reminder user — receives the configured Sunday-evening push per V1/features.md ("Sunday evening default; skipping is itself logged but never penalized")
  • Skipped-last-week user — closed late or missed; this Sunday's review must not shame the skip per the no-shame floor
  • Multi-quiet-day user — has had quiet days; the review's kept, partial, rest, and quiet metrics must remain descriptive, never punitive
  • Tenant-bound institutional user — institutional review cadence may differ; the Sunday default is configurable per tenant
  • Power-user reviewer — prefers the deeper internal surface at /domains/arete/plan-review

Pre-conditions#

  • Signed-in session; middleware permits /arete, /arete/review, /arete/coaching
  • getAreteReview() returns AreteReviewData ({ weekLabel, acts, kpi, days }); BFF mapping comment marks /arete/reviews/:weekId
  • Notification permission previously granted (push delivery walked in install-as-pwa.md §13)
  • Lilith coach persona on Arete with reflective tone band per V1/features.md#persona-taxonomy-tone-band-catalog-and-crisis-recovery-journey
  • No crisis frame active (crisis policy supersedes)

Steps#

1. Sunday push or in-app reminder fires#

  • Account-visible reminder category: /profile/notifications renders arete-weekly-review with Cadence · weekly, backed by the real Arete domain reminder preference; profile-notifications-index patches /v1/notifications/preferences/domains/arete and proves the weekly-review category turns off without turning general reminders off.
  • In-app fallback banner: /arete reads the same real Arete reminder preference through /v1/arete/room, renders the Sunday-evening arete-weekly-review banner when the in-app modality is enabled, and removes it after the Arete reminder preference is disabled.
  • OS push delivery per cadence config (default: Sunday evening), if granted
  • Reminder copy: humane copy ("a quiet moment, the week kept"); never "you missed your review" / "you broke your streak"
  • Push target: /arete/review; tap → service worker notificationclick listener focuses the existing tab or cold-launches (see install-as-pwa.md §13)
  • In-app target: banner CTA opens /arete/review
  • Telemetry: arete_review_reminder_shown emits after the BFF-backed banner mounts on /arete

2. Arrive on /arete/review#

page.tsx is a thin server component: await getAreteReview()<AreteReview>, inside LWebShell with LCustomerNav active="today".

  • Page server-blocks on getAreteReview() (no loading.tsx)
  • Masthead reads "Arete · sunday review" / data.weekLabel / "four acts · twenty minutes", display title "Sunday. Look back, gently.", lede about Celebrate · Notice · Choose · Invite
  • Verify: customer/04-arete/arete-review.md layout regions

3. Walk Act I — Celebrate (look back)#

Four acts stack vertically on the left (1.4fr). Each act renders a header row (eyebrow / title / LCode duration), a mixed-emphasis body, and a two-column grid of list items.

  • Act I header eyebrow reads "act I · what held" (accent if a.accent)
  • Body composes a.bodyParts — mixed text with emphasized (accent italic) and chip (highlight bg) inline spans
  • List items in rounded outlined cards; copy must not shame — celebrate names what went well per V1/features.md

4. Act II — Acknowledge / Notice#

  • Act II header: "act II · what slipped"; body names patterns without inviting shame per the no-shame floor (same rule as arete-streak-recovery.md §4)
  • List items are named patterns (e.g., "Wednesday dip", "evening practice slipped")

5. Act III — Choose / Pivot#

  • Act III header: "act III · one change"; body asks the user to choose what to commit to next week per V1/features.md
  • List items are candidate commitments; per-view file flags no per-act completion state today (user cannot mark Choose individually)

6. Act IV — Invite / Commit#

  • Act IV header: "act IV · into the week"; body invites release per V1/features.md
  • List items are release / commitment statements

7. KPIs + journal lines (right column)#

  • "The week, kept" renders all four data.kpi metrics in one flexible row; each tuple [k, v, c] renders big serif numeral coloured by c (accent / ink / muted via kpiColor helper)
  • "Mood thread" SVG (aria-hidden) draws a smooth quadratic curve across mon–sun; caption renders data.moodCaption so the named weekly pattern can adapt with the review data
  • "What you wrote" lists data.days[i] = [day, txt] with date code + italic text; no per-entry link to the journal route

8. Continuity card and next-week plan#

Per V1/features.md ("continuity card, next-practice recommendations, plan adjustments saved with user approval"), the review output composes into a continuity card.

  • Footer note: "The review is yours; Lilith never alters a sentence. She might suggest a phrase in the margin."
  • Click the margin-suggestion reveal; a data-backed phrase appears beside the footer note, aria-expanded flips to true, and the rendered review body remains unchanged
  • Click "Save as private letter" (AreteReviewClose button); client POSTs /v1/arete/review/close with { weekLabel, action: 'saved-private' } and renders data-arete-review-close-state="kept-private"
  • Click "Close the week" (AreteReviewClose button); client POSTs /v1/arete/review/close with { weekLabel, action: 'closed' } and renders data-arete-review-close-state="week-closed". The same persisted closure now feeds /arete through /v1/arete/room as a continuity card; richer plan adjustments remain subject to user approval per feature spec
  • Telemetry: after the real BFF close/save response succeeds, AreteReviewClose emits arete_weekly_review_closed with surface: 'arete_review', sourcePath: '/arete/review', weekLabel, action, state, and closureId

9. Return to /arete and verify continuity#

  • Navigate back to /arete; continuity card reads back the latest week-closed / kept-private review closure from /v1/arete/room
  • Home rail HomeAretePracticeSection reflects adjustments per customer/04-arete/arete.md data contract (BFF mapping notes /arete coaching.latest-suggestion, /arete evening-prompt.today)
  • Lilith's letter at /arete/coaching may surface follow-up patterns named during the review (lagged — see arete-create-habit.md §10 for the coaching cadence)

Post-conditions#

  • Four acts rendered with mixed-emphasis bodies and list cards
  • KPI tiles, mood SVG, day-by-day journal lines rendered without shaming language
  • If "Close the week" pressed: closure persists to /v1/arete/review/closed and reads back on /arete; richer next-week plan adjustments remain an explicit product gap
  • If either terminal footer action succeeds: the browser emits arete_weekly_review_closed with the exact persisted closure action/state
  • A shown in-app reminder emits arete_review_reminder_shown; the product requirement to log a skipped review without penalizing it remains open

Failure modes#

  • "Save as private letter" / "Close the week" are wiredAreteReviewClose replaced the inert footer buttons; both actions POST /v1/arete/review/close and render BFF-backed status (kept-private / week-closed)
  • No per-act completion state — user cannot mark Celebrate / Notice / Choose / Invite individually
  • No journal input on the review pagedata.days is read-only; "Save as private letter" persists the review closure, not editable journal text
  • Mood-thread caption hardcoded — fixed 2026-06-24: AreteReviewData.moodCaption feeds the visible caption, with component coverage proving a custom caption replaces the default fixture text
  • Margin-suggestion affordance missing — fixed 2026-06-24: AreteReviewMarginSuggestion reveals data.marginSuggestion with aria-expanded/aria-controls and does not mutate the review body
  • Sunday push not granted — if push declined, the in-app banner is the only entry; user may miss the reminder
  • Crisis frame active — recovery / weekly-review prompts suspended; safety surface takes priority per crisis-aware-tone-policy.md
  • Shaming copy regression — any prose using "you broke your streak" or "you missed your review" violates the no-shame floor (same rule as arete-streak-recovery.md)

E2E coverage#

Spec: apps/oshun/web/e2e/arete-weekly-review.spec.ts — as of 2026-06-25, the four-act specimen is asserted through stable data-arete-review-* anchors for page counts, masthead, every act/body/list cell, every KPI tile/value/color, the mood chart/caption, all seven journal rows, and the footer action region.

Spec: apps/oshun/web/e2e/arete-review-reminder.spec.ts — step 1's locally-verifiable reminder entry is now driven end-to-end: the test patches the real Arete notification preference into in-app fallback mode, loads /arete, asserts the BFF-backed Sunday-evening reminder card, proves humane copy/no-shame wording, captures arete_review_reminder_shown, clicks through to /arete/review, then disables the Arete reminder preference and proves the banner disappears.

Spec (wave-7, close interaction): apps/oshun/web/e2e/arete-review-close.spec.ts — step 8 is now driven end-to-end: the AreteReviewClose island replaced the inert <LBtn>s, so "Close the week" POSTs /v1/arete/review/close and renders a week-closed confirmation, and "Save as private letter" POSTs the same route to render kept-private. Both terminal actions now assert the arete_weekly_review_closed analytics event after the real BFF response. The four-act review body above it stays render-only; only the close/save row is wired.

Step Test name Status
2 page loads with masthead week-label, four-act lede, and Lilith tone identity covered via page/masthead/count anchors
3 Act I — Celebrate: eyebrow, title, mixed-emphasis body, list cards covered via act/body/list anchors
4 Act II — Notice: eyebrow, pattern body, list items covered via act/body/list anchors
5 Act III — Choose: eyebrow, body, list items covered via act/body/list anchors
6 Act IV — Invite: eyebrow, body, list items covered via act/body/list anchors
7 KPI tiles render all four labels and numeric values covered via per-KPI value/color anchors
7 Mood-thread SVG aria-hidden; data-backed mood caption present covered via mood chart/caption anchors
7 Journal day lines render all seven days with italic entry text covered via per-row day/text anchors
8 Footer note present; Save-as-letter and Close-the-week buttons present covered via footer/action anchors
8 Margin suggestion reveal toggles a data-backed phrase without body mutation covered
8 Close the week → POST /v1/arete/review/close → week-closed confirmation covered (arete-review-close.spec.ts)
8 Save as private letter → POST /v1/arete/review/close → kept-private covered (arete-review-close.spec.ts)
8 Close/save telemetry emits arete_weekly_review_closed after BFF success covered (arete-review-close.spec.ts)
9 Return to /arete and verify weekly-review continuity card covered (arete-review-close.spec.ts via /v1/arete/room read-back)
No-shame floor: shaming phrases absent from rendered page covered
1 Account notification index exposes the Arete weekly-review reminder category covered (profile-notifications-index: real Arete preference PATCH + reload)
1 In-app reminder fallback on /arete covered (arete-review-reminder.spec.ts: real preference PATCH + telemetry)
1 Sunday OS push delivery not covered — push delivery requires OS notification infra
9 Home rail / coaching follow-up plan adjustments not covered — richer review-derived plan adjustment payload is not modeled yet

Coverage depth: partial — see coverage.md. /arete/review is a server-rendered specimen (getAreteReviewFixture) for the four-act body. The specimen layer is now row/cell-level: the browser test checks route counts, masthead text, every act's identity/title/duration/body-part kind, every list item, every KPI value/color, the mood chart/caption, all seven journal rows, and the footer action region through stable anchors rather than broad page text. The close interaction is wired separately: the AreteReviewClose island replaced the inert buttons, so "Close the week" and "Save as private letter" POST /v1/arete/review/close, render week-closed / kept-private, emit arete_weekly_review_closed with the persisted action/state/week label/closure id, and return to /arete to assert the persisted closure through /v1/arete/room (arete-review-close.spec.ts). The same /v1/arete/room response now also carries the member's weeklyReviewReminder snapshot from the real notification preference store, and arete-review-reminder.spec.ts proves the in-app fallback card, no-shame copy, arete_review_reminder_shown, /arete/review CTA, and preference-off removal. The four-act content still has no per-act interaction, but the journey is no longer shallow — its render specimen, terminal close action, close telemetry, reminder entry, and Arete-hub read-back are all covered, and the mood-thread caption is a review-data contract instead of JSX literal copy. The footer margin-suggestion promise is also wired as a data-backed reveal interaction.

Uncovered: step 1's actual Sunday OS push scheduler/delivery (the account notification index and /arete in-app fallback are covered, but OS notification delivery remains separate infra); the four-act body's per-act completion state (no per-act onClick); review-derived Home rail / coaching follow-up plan adjustments. The margin suggestion, close/save action, reminder impression, close telemetry, and /arete continuity read-back are now covered end-to-end.

Note — the /arete/review route is not inert. The same route also mounts AreteReviewDraftRun (apps/oshun/web/src/components/lilith/arete.tsx), a fully wired agent surface that POSTs the real /v1/agentic/runs lifecycle (request → approve → queued / discard → cancelled) against the live BFF. That surface is a different feature from the four-act weekly review and is covered by agentic-pipeline-runnow-arete.spec.ts (the agentic-pipeline-customer-invocation journey). So "no write path is wired on /arete/review" would be wrong. The four-act review's close/save footer is also wired through AreteReviewClose; remaining gaps are the static act body and richer plan-adjustment read-back.

Per-view files touched by this journey#

Cross-references#

Open questions / known gaps#

  • Add /arete continuity-card read-back coverage after /v1/arete/review/close; the closure persists via /v1/arete/review/closed and the hub continuity card now reads it through /v1/arete/room
  • Confirm the cadence config surface — where does the user set Sunday vs another day per the feature spec's "configurable" promise? The account notification index now shows the weekly-review reminder category and the /profile?path=notifications handoff, but no day-of-week selector is modeled yet.
  • Document the plan-adjustment approval flow — V1/features.md requires "plan adjustments saved with user approval"; where is the per-adjustment Approve / Defer affordance?
  • Wire the margin-suggestion affordance, or remove the claim — fixed by AreteReviewMarginSuggestion
  • Confirm the continuity card on /arete reads from the same BFF review-closure store as /v1/arete/review/closed — namespace drift risk per the arete-create-habit.md finding
  • Document the per-tenant cadence override path for institutional reviewers