Context. surface customer · domain arete · route /domains/arete/balance · auth signed-in · source apps/oshun/web/src/app/domains/arete/balance/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
Purpose#
Internal /domains/arete/* alternate surface for life-balance assessment: a
4-tab workspace (wheel, assessment, history/trends, suggestions to improve).
Backed by fixture constants (BALANCE_DOMAINS, BALANCE_SCORES_CURRENT,
BALANCE_ASSESSMENT). Renders an SVG radar/spider chart of the eight life
domains (career, finance, health, relationships, personal-growth,
fun-recreation, physical-environment, spirituality).
Entry points#
- Direct URL / bookmark — yes (signed-in)
- No link from
/aretepolished surface — verify
Layout regions#
page.tsx is a 'use client' page: SR-only "Life Balance · Arete · OSHUN"
heading + <AreteLifeBalance />. Component at
apps/oshun/web/src/components/domains/arete/AreteLifeBalance.tsx.
- Container:
max-width: 900px; padding: 24px - Header: Scale icon + h2 "Life Balance" + subtitle "Assess and optimize balance across all areas of your life"
- Tab bar (4 tabs):
wheel— Balance Wheel (Scale icon)assessment— Assessment (BarChart3 icon)history— Trends (History icon)suggestions— Improve (Lightbulb icon)
- Content area (per active tab):
wheel→<BalanceWheelView />— SVG radar chart with current scores (filled accent polygon) and previous scores (lighter outline polygon).getPoint(index, value)projects each domain to a point on a radius of 160 around center (200, 200). Domain icons (DOMAIN_ICONS: Briefcase / DollarSign / Heart / Users / TrendingUp / Smile / Home / Sparkles) rendered at the perimeter. Overall score (mean ofscores[].score) displayed.assessment→<AssessmentView />history→<TrendsView />suggestions→<SuggestionsView />
States#
- Loading — N/A: client component with sync fixture import
- Hovered domain —
hoveredDomainstate lights up the spider chart segment (verify in DOM) - Tab switching — instant
- Empty
scores—overallScorewould compute as'0'; the radar polygon would be empty (no points) - Error (recoverable) — relies on app-level error boundary
- Offline — purely client; identical offline once loaded
- Gated — N/A
- Standalone PWA — no shell chrome around the page; renders bare
Interactions#
Tab bar (4 tabs)#
- Balance Wheel / Assessment / Trends / Improve (buttons)
- Function:
setActiveTab(tab.id) - Keyboard / SR:
<button>with norole="tab", noaria-selected - Active style: accent tint background, accent foreground
- Telemetry: none
- Function:
Balance wheel (SVG)#
- Radar polygon (path) — fill based on
radarPath, derived from currentscoresprojected viagetPoint - Previous polygon (path) — outlined polygon driven by
previousPath; shows score history overlay - Domain hotspots —
hoveredDomainstate suggests there's a hover affordance; verify which element receivesonMouseEnter/onMouseLeave - Domain icons — rendered at each axis end; verify whether clickable
Data & contracts#
- Reads: import-time
BALANCE_DOMAINS,BALANCE_SCORES_CURRENT,BALANCE_ASSESSMENTfrom@/lib/arete/arete-extended-simulation. No BFF calls. - Writes: none —
setScoresmutations are local - Realtime: none
- Caching: client bundle only
- Auth/role check: app-level middleware
Cross-references#
- Domain hub:
arete.md - Component source:
apps/oshun/web/src/components/domains/arete/AreteLifeBalance.tsx - Simulation data:
apps/oshun/web/src/lib/arete/arete-extended-simulation.ts - Types:
apps/oshun/web/src/lib/arete/arete-extended-types.ts(BalanceDomain,BalanceScore)
Open questions / known gaps#
- No counterpart in
/arete/*polished routes — balance is a domains-namespace-only surface - No shared chrome with the polished
/areteLilith room - Score mutations don't persist across reloads (no API write)
- Verify hover behaviour on radar —
hoveredDomainstate exists but the source needs deeper read to confirm which mouseevents target it and what the hover affordance looks like