---
path: /arete/review
surface: customer
domain: arete
auth: signed-in
source: apps/oshun/web/src/app/arete/review/page.tsx
status: walked
last_walked:
  '2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data
  (2xx), console/page-errors, expected content, screenshot verified; live
  screen-reader, touch, offline, and telemetry-delivery checks pending a manual
  AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md; content
  re-verified 2026-06-03 against current source; 2026-06-30 close/save telemetry
  re-walked in arete-review-close.spec.ts'
---

# Arete · the weekly review

## Purpose

"Celebrate · Notice · Choose · Invite. Four acts, twenty minutes, on a Sunday."
A guided weekly review with the four acts in order, a sidebar of KPIs, mood
thread, and one-per-evening journal lines. Renders
`<AreteReview data={await getAreteReview()} />`.

## Entry points

- **From `/arete` sub-nav "Weekly review" tab** — the `LSubNav` item carries
  `href="/arete/review"` and navigates here
- **Sunday reminder push** — inferred from "Sunday. Look back, gently." body
- **From `/arete/coaching`** — Lilith's letter references "the week" and may
  link back here (no explicit link in source)
- **Direct URL / bookmark** — yes (signed-in)

## Layout regions

`page.tsx` is a thin server component: `await getAreteReview()` →
`<AreteReview>`. Component lives at
`apps/oshun/web/src/components/lilith/arete.tsx` line 1108 — an `LWebShell` with
`LCustomerNav active="today"`.

- **Header**: `LCustomerNav active="today"`
- **Masthead** (`ArMast`): left "Arete · sunday review", mid `data.weekLabel`,
  right "four acts · twenty minutes", big "Sunday. _Look back, gently._", lede
  about Celebrate · Notice · Choose · Invite
- **Main, left (1.4fr)**: vertical stack of four act blocks (per `data.acts`).
  Each act renders:
  - Header row: "act {num} · {kicker}" eyebrow (accent if `a.accent`), big
    italic title, `LCode` duration on the right
  - Body: mixed text with `emphasized` (accent italic) and `chip` (highlight bg)
    inline spans from `a.bodyParts`
  - Two-column grid of `a.list` items in rounded outlined cards
- **Aside, right (1fr)**:
  - "The week, kept" — `data.kpi` 3-up: each tuple `[k, v, c]` renders big serif
    numeral colored by `c` ('accent' / 'ink' / muted)
  - "Mood thread" — `aria-hidden` SVG curve across the week (mon–sun); body
    renders `data.moodCaption`
  - "What you wrote" — list of `data.days[i] = [day, txt]` lines with date
    code + italic text
- **Footer row** (`borderTop: 1px solid L.ink`):
  - Note: "The review is yours; Lilith never alters a sentence. She might
    suggest a phrase in the margin."
  - `AreteReviewMarginSuggestion` reveal button backed by
    `data.marginSuggestion`
  - "Save as private letter" (ghost md) + "Close the week" (primary md)

## Automation anchors

- Root: `data-arete-review-page` with `data-arete-review-week-label`,
  `data-arete-review-act-count`, `data-arete-review-kpi-count`, and
  `data-arete-review-journal-day-count`
- Masthead and layout: `data-arete-review-masthead`, `data-arete-review-layout`,
  `data-arete-review-acts`, and `data-arete-review-sidebar`
- Act blocks: each `data-arete-review-act={num}` carries index/title/kicker/
  duration/accent attributes, plus `data-arete-review-act-eyebrow`,
  `data-arete-review-act-title-text`, `data-arete-review-act-duration-text`,
  `data-arete-review-act-body`, per body part kind,
  `data-arete-review-act-list`, and per list item index
- Sidebar: `data-arete-review-kpis` with per `data-arete-review-kpi={label}`
  value/color cells; `data-arete-review-mood` with
  `data-arete-review-mood-chart` and `data-arete-review-mood-caption`; and
  `data-arete-review-journal` with per-row day/text cells
- Footer: `data-arete-review-footer`, `data-arete-review-footer-note`, and
  `data-arete-review-footer-actions`

## States

- [ ] **Loading** — server-awaited; no `loading.tsx` at this route
- [x] **Populated (default fixture)** — four acts, KPI tiles, mood SVG,
      day-by-day journal lines render
- [ ] **Mid-act (partial)** — N/A: the page renders all four acts at once; no
      "active act" progress indicator
- [ ] **Empty acts / days / kpi** — empty arrays render no rows (no empty-state
      copy)
- [ ] **Error (recoverable)** — relies on parent error boundary
- [ ] **Offline** — no explicit handling
- [ ] **Gated** — N/A
- [ ] **Standalone PWA** — renders cleanly within `LWebShell`

## Interactions

### Act blocks (per `data.acts`)

- [x] **Act block** — header, body (mixed emphasis), list items
  - Function: presentational only — no inputs, no completion checks

### KPI tiles (per `data.kpi`)

- [x] **KPI tile** — big numeral + label eyebrow
  - Color: derived from third tuple entry — `accent` → `L.accent`, `ink` →
    `L.ink`, else `L.muted` (`kpiColor` helper)
  - Function: presentational only

### Mood SVG

- [x] **Mood thread chart** — `aria-hidden="true"`; smooth quadratic curve
      across mon–sun
  - Function: presentational only
  - Caption renders `data.moodCaption`

### Journal lines (per `data.days`)

- [x] **Day row** — date code + italic text
  - Function: presentational only — no entry-level link to journal route

### Footer actions

- [x] **Margin suggestion** (button in `AreteReviewMarginSuggestion`)
  - Function: toggles a data-backed phrase beside the footer note without
    mutating the review body
  - Screen reader: button exposes `aria-expanded` and `aria-controls`
- [x] **"Save as private letter"** (button in `AreteReviewClose`)
  - Function: POSTs `/v1/arete/review/close` with action `saved-private` and
    renders `data-arete-review-close-state="kept-private"`
  - Telemetry: after the BFF closure response succeeds, emits
    `arete_weekly_review_closed` with `action: 'saved-private'`,
    `state: 'kept-private'`, `weekLabel`, `closureId`, and
    `sourcePath: '/arete/review'`
- [x] **"Close the week"** (button in `AreteReviewClose`)
  - Function: POSTs `/v1/arete/review/close` with action `closed` and renders
    `data-arete-review-close-state="week-closed"`
  - Telemetry: after the BFF closure response succeeds, emits
    `arete_weekly_review_closed` with `action: 'closed'`,
    `state: 'week-closed'`, `weekLabel`, `closureId`, and
    `sourcePath: '/arete/review'`

## Data & contracts

- **Reads**: `getAreteReview()` from `@/lib/lilith-data/arete-depth` — returns
  `AreteReviewData` ({ weekLabel, acts, kpi, moodCaption, marginSuggestion, days
  }). BFF mapping comment: `getAreteReview ← /arete/reviews/:weekId`.
- **Writes**: `AreteReviewClose` POSTs `/v1/arete/review/close` for
  `saved-private` and `closed`; `/arete` reads the stored closure through
  `/v1/arete/room`
- **Telemetry**: `apps/oshun/web/src/analytics/areteReviewTelemetry.ts` emits
  `arete_weekly_review_closed` only after the persisted close/save envelope is
  returned by the BFF.
- **Realtime**: none
- **Caching**: server fetch, default Next.js cache
- **Auth/role check**: app-level middleware

## Cross-references

- Domain hub: [`arete.md`](./arete.md)
- Plan / Goal siblings: [`arete-plan.md`](./arete-plan.md),
  [`arete-goal.md`](./arete-goal.md), [`arete-coaching.md`](./arete-coaching.md)
- Domains-namespace alternate:
  [`domains-arete-plan-review.md`](./domains-arete-plan-review.md) — internal
  plan-review workspace with reflection drafts and assistant handoff
- Component source: `apps/oshun/web/src/components/lilith/arete.tsx` (line 1108,
  `AreteReview`)
- Data: `apps/oshun/web/src/lib/lilith-data/arete-depth.ts`
  (`getAreteReviewFixture`)
- Feature spec: [`V1/features.md`](../../../V1/features.md#arete)

## Open questions / known gaps

- [x] "Save as private letter" and "Close the week" persist through
      `AreteReviewClose`, emit `arete_weekly_review_closed` after BFF success,
      and read back on `/arete`
- [ ] No per-act completion state — the user can't mark Celebrate / Notice /
      Choose / Invite individually
- [ ] No journaling input on this page — `data.days` is read-only; the "Save as
      private letter" CTA implies an output that isn't wired here
- [x] Mood-thread caption is data-driven via `AreteReviewData.moodCaption`
- [x] Promise text "Lilith never alters a sentence. She might suggest a phrase
      in the margin." — `AreteReviewMarginSuggestion` now reveals the
      data-backed phrase without altering the review text
