Context. surface customer · domain arete · route /arete/streak · auth signed-in · source apps/oshun/web/src/app/arete/streak/page.tsx
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
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 —HomeAretePracticeSectionshows streak indicator; verify whether it deep-links here - From
/areteintention rows — each row shows a "{streakDays}-day streak" eyebrow but nohrefis wired - Cross-domain from
/arete/streakitself — the "Begin" CTA links into the Tara sit player (/tara/sit/when-the-mind-wanders); noteTaraRoomhas 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:
LWebShellwithtop={<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:
PhoneFramewithlabel="Arete · streak"andcaption="Day 47, gently. Two quiet days, folded in." - Phone contents:
<AreteStreak data={data} />—apps/oshun/web/src/components/lilith/arete.tsxline 172- Status bar (
LStatusBar) - Top row: "Arete · today" eyebrow + "day {dayNumber}" accent eyebrow (fixture: day 109)
- Italic lede "A practice, gently kept."
- Huge
data.streakCountnumeral (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 asrole="list"with per-cellrole="listitem"labels. Cell color is derived per state:kept= accent,half=#d99777,rest= rule color,today= ink with 2px accent border, elserule2; 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)
- Status bar (
States#
- Loading — server-awaited; no
loading.tsxat 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:
streakCountis 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#
- 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, andtitlewith date + state - Today cell gets a 2px accent border
"Adjust"#
- "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
- Function: navigates to
"Begin"#
- "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
- Function: cross-domain link — navigates to the Tara sit player at
Data & contracts#
- Reads:
getAreteStreak()from@/lib/lilith-data/arete-depth— returnsAreteStreakData({ 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=adjustand/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 - Recovery partner:
arete-recovery.md— what triggers when "three quiet days in a row" condition is met - Cross-domain:
../03-tara/tara.md— this surface's "Begin" CTA links into the Tara sit player (TaraRoomitself 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
Open questions / known gaps#
- "Adjust" and "Begin" CTAs are wired as navigation links
(
/arete/plan?intent=adjustand 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
(
generateStreakHeatmapinarete-depth.ts) and a fixedweekHeatmapStartDateIso, 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/areteroom intention rows (per-habit streak eyebrows) — verify which streaks roll up here