---
path: /arete/streak
surface: customer
domain: arete
auth: signed-in
source: apps/oshun/web/src/app/arete/streak/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'
---

# Arete · the humane streak

## Purpose

"A practice, gently kept — rest days are part of it; quiet days do not break
it." The streak surface: day count, six-week heatmap, an explicit promise about
rest and check-ins, and today's invitation. Rendered as a phone shell inside a
desktop frame.

## Entry points

- **From `/` home rail Arete practice section** — `HomeAretePracticeSection`
  shows streak indicator; verify whether it deep-links here
- **From `/arete` intention rows** — each row shows a "{streakDays}-day streak"
  eyebrow but no `href` is wired
- **Cross-domain from `/arete/streak` itself** — the "Begin" CTA links into the
  Tara sit player (`/tara/sit/when-the-mind-wanders`); note `TaraRoom` has no
  streak/continuity panel that links back here
- **Direct URL / bookmark** — yes (signed-in)

## Layout regions

`page.tsx` is **not** a thin server component — it wraps a `PhoneFrame` inside
an `LWebShell` with a masthead and lede. Layout:

- **Outer**: `LWebShell` with `top={<LCustomerNav active="today" />}`
- **Outer body**: `padding: 32px 56px 80px; max-width: 720px`
- **Masthead**: `LMasthead` — left "Specimen · Arete mobile", right "375 × 812",
  kicker "A practice, gently kept", title "The _streak._"
- **Lede block**: `LEyebrow` "The promise" + italic body "A streak should never
  punish a Sunday off. Two rest days a week are part of the practice. Three
  quiet days in a row, and Lilith will check in — never before."
- **Phone frame**: `PhoneFrame` with `label="Arete · streak"` and
  `caption="Day 47, gently. Two quiet days, folded in."`
- **Phone contents**: `<AreteStreak data={data} />` —
  `apps/oshun/web/src/components/lilith/arete.tsx` line 172
  - Status bar (`LStatusBar`)
  - Top row: "Arete · today" eyebrow + "day {dayNumber}" accent eyebrow
    (fixture: day 109)
  - Italic lede "A practice, gently kept."
  - Huge `data.streakCount` numeral (fixture: 47) + smaller "days" accent italic
  - Italic muted `data.streakNote` ("Two quiet days are folded into the count,
    as we agreed.")
  - "Last six weeks" heatmap — 42-cell grid (`data.weekHeatmap`) exposed as
    `role="list"` with per-cell `role="listitem"` labels. Cell color is derived
    per state: `kept` = accent, `half` = `#d99777`, `rest` = rule color, `today`
    = ink with 2px accent border, else `rule2`; each cell's accessible label
    includes its fixture date and state.
  - Legend row: "● kept · ● partial · ○ rest · · quiet"
  - "The promise" callout card (light paper bg) with `data.promise`
  - "Today's invitation" italic body from `data.todaysInvitation`
  - Bottom action row (absolute-positioned): "Adjust" ghost lg (flex 1, `href`
    `/arete/plan?intent=adjust`) + "Begin" primary lg (flex 2, `href`
    `/tara/sit/when-the-mind-wanders`)
  - Home indicator (`LHomeIndicator`)

## States

- [ ] **Loading** — server-awaited; no `loading.tsx` at this route
- [ ] **Populated (default fixture)** — day 109, streak 47, full heatmap,
      promise + invitation
- [ ] **Recovery state (3+ quiet days)** — N/A here; recovery is a separate
      route `/arete/recovery`. The streak surface still renders even when quiet
      — see Open questions
- [ ] **Streak == 0** — N/A: `streakCount` is shown as a big numeral; "0 days"
      would render literally with the small italic "days" suffix
- [ ] **Promise tone (V1 feature requirement)** — body and promise read
      "gently", "never punish a Sunday off", "Lilith will check in — never
      before"; no shaming copy ✓ matches V1/features.md humane-recovery
      requirement
- [ ] **Error (recoverable)** — relies on parent error boundary
- [ ] **Offline** — no explicit handling
- [ ] **Gated** — N/A
- [ ] **Standalone PWA** — page is a desktop frame around a phone shell; verify
      on actual mobile viewport (page hardcodes `max-width: 720px`)

## Interactions

### Heatmap cells

- [x] **Heatmap cell** — square cell colored by state from `data.weekHeatmap[i]`
  - Function: presentational only — no click
  - Keyboard / SR: parent grid is labelled "Last six weeks of Arete practice";
    each cell has `role="listitem"`, `aria-label`, and `title` with date + state
  - Today cell gets a 2px accent border

### "Adjust"

- [x] **"Adjust"** — `LBtn kind="ghost" size="lg"`
      (`href="/arete/plan?intent=adjust"`, flex 1)
  - Function: navigates to `/arete/plan?intent=adjust` (line 341) — the
    plan/adjust surface

### "Begin"

- [x] **"Begin"** — `LBtn kind="primary" size="lg"`
      (`href="/tara/sit/when-the-mind-wanders"`, flex 2)
  - Function: cross-domain link — navigates to the Tara sit player at
    `/tara/sit/when-the-mind-wanders` (line 344), starting today's session

## Data & contracts

- **Reads**: `getAreteStreak()` from `@/lib/lilith-data/arete-depth` — returns
  `AreteStreakData` ({ dayNumber, streakCount, streakNote,
  weekHeatmapStartDateIso, weekHeatmap, promise, todaysInvitation }). BFF
  mapping comment: `getAreteStreak ← /arete/streak`.
- **Writes**: none — "Adjust" and "Begin" are navigation links (to
  `/arete/plan?intent=adjust` and `/tara/sit/when-the-mind-wanders`), not
  mutations
- **Realtime**: none
- **Caching**: server fetch, default Next.js cache
- **Auth/role check**: app-level middleware

## Cross-references

- Domain hub: [`arete.md`](./arete.md)
- Recovery partner: [`arete-recovery.md`](./arete-recovery.md) — what triggers
  when "three quiet days in a row" condition is met
- Cross-domain: [`../03-tara/tara.md`](../03-tara/tara.md) — this surface's
  "Begin" CTA links into the Tara sit player (`TaraRoom` itself has no streak
  panel)
- Component source: `apps/oshun/web/src/components/lilith/arete.tsx` (line 172,
  `AreteStreak`)
- Data: `apps/oshun/web/src/lib/lilith-data/arete-depth.ts`
  (`getAreteStreakFixture`)
- Phone frame: `apps/oshun/web/src/components/lilith/mobile.tsx`
- Feature spec: [`V1/features.md`](../../../V1/features.md#arete)

## Open questions / known gaps

- [x] "Adjust" and "Begin" CTAs are wired as navigation links
      (`/arete/plan?intent=adjust` and the cross-domain
      `/tara/sit/when-the-mind-wanders`); no streak-mutation write exists yet
- [ ] The 42-cell heatmap is generated from arithmetic in the fixture
      (`generateStreakHeatmap` in `arete-depth.ts`) and a fixed
      `weekHeatmapStartDateIso`, not from real per-day data
- [ ] The page wraps a phone shell inside a desktop frame ("Specimen · Arete
      mobile" label) — same specimen pattern as `/arete/recovery`. Verify
      whether this is the actual mobile customer surface or a design specimen
- [ ] Relationship between `/arete/streak` (presentational, single practice) and
      the `/arete` room intention rows (per-habit streak eyebrows) — verify
      which streaks roll up here
