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

# Arete Progress Maps Workspace

## Purpose

Internal `/domains/arete/*` progress-maps workspace. "Read momentum as a map,
not just a score." Tracks where progress is compounding, where it's slipping,
and which patterns are strong enough to carry into the next review. Tied to
`@oshun/domain-arete` canonical builders for friction summary, coaching shell,
and a progress-map export.

## Entry points

- **Direct URL / bookmark** — yes (signed-in)
- **Back navigation** — page passes `onBack={() => router.back()}`
- **No link from `/arete` polished surface** — verify

## Layout regions

`page.tsx` is a `'use client'` page using `useRouter()`. Renders
`<AreteProgressMapsWorkspace onBack={() => router.back()} />`. Component at
`apps/oshun/web/src/components/domains/arete/AreteProgressMapsWorkspace.tsx`.

- **Container (section)**: cream-paper radial gradient + linear gradient
  background; column flex; padding 24px (desktop) / 16px
- **Header tile**: Back button (`aria-label="Go back"`), eyebrow "Arete progress
  maps" + BarChart3 icon, h1 "Read momentum as a map, not just a score.", lede
  paragraph, "Open analysis assistant" CTA (dispatches
  `dispatchOshunAssistantOpen` with focus object, pattern cluster, and momentum
  note in the seeded prompt)
- **Window selector** (`role="group"`, `aria-label="Progress map time window"`):
  3 pill buttons — `weekly`, `monthly`, `quarterly`
  (`data-arete-progress-maps-period`, `aria-pressed={active}`,
  `aria-label="Show <window> progress map"`)
- **Below window selector** (per source, continues beyond line ~881):
  - **Focus entity filter** — `entityFilter` state with options `all` / `goal` /
    `habit`; selectable filter
  - **Focus entity list** — driven by `filteredEntities` from concat of `goals`
    and `habits` fixtures (each is a `FocusEntity` with kind, title,
    progressPercent, momentumLabel, patternLabel)
  - **Pattern cluster list** — driven by `patternClusters` fixture (each is a
    `PatternCluster`)
  - **Chart strip** — `chartProfiles[window]` array of bars (visual momentum bar
    chart)
  - **Friction summary** — `summarizeAreteFrictionLogs(frictionLogs)` → primary
    category, evidence
  - **Coaching brief** —
    `buildAreteCoachingSummaryShellModel({ summary, frictionLogs })` produces
    card title and assistant seededPrompt
  - **Artifact actions** — `AreteArtifactActionPanel` save / export / share via
    `saveAreteArtifact` / `triggerAreteArtifactDownload` /
    `buildAreteProgressMapExport`

## States

- [ ] **Loading** — N/A: client component with sync builders
- [ ] **Window toggled (weekly / monthly / quarterly)** — re-derives `chartBars`
      from `chartProfiles[window]`, updates the progress summary, regenerates
      the coaching brief
- [ ] **Entity filter toggled** — `entityFilter` filters `goals ∪ habits` to a
      `kind`
- [ ] **Entity selected** — `setSelectedEntityId(...)`; if filtered out, falls
      back to first filtered, then to original list, then to first entity
- [ ] **Cluster selected** — `setSelectedClusterId(...)`
- [ ] **Artifact saved** — `setArtifactSavedAt` updates after save; the
      `artifactId` is `arete-progress-map:{window}:{entityId}:{clusterId}` so
      changing any of the three rotates the saved record
- [ ] **Saved-at hydrated** — `useEffect` reads localStorage for the current
      `artifactId`
- [ ] **Error (recoverable)** — relies on app-level error boundary
- [ ] **Offline** — purely client; identical offline
- [ ] **Gated** — N/A (no policy gates on this surface in source head)
- [ ] **Standalone PWA** — no shell chrome around the page

## Interactions

### Top bar

- [ ] **Back button** (`aria-label="Go back"`)
  - Function: calls `router.back()` via `onBack` prop
- [ ] **"Open analysis assistant"** (button,
      `data-arete-progress-maps-open-assistant`)
  - Function: dispatches `dispatchOshunAssistantOpen` with source
    `arete-progress-maps:<window>` and a prompt referencing the selected entity,
    cluster, and momentum label
  - Touch target: padding `12px 16px`

### Window selector (3 buttons)

- [ ] **Weekly / Monthly / Quarterly** (pill buttons)
  - Function: `setWindow(option)`
  - `aria-pressed={active}`, `aria-label="Show <window> progress map"`
  - `data-arete-progress-maps-period`

### Below-the-fold (per source body)

- [ ] **Entity filter toggle** — verify in the lower component body
- [ ] **Entity selector buttons** — `setSelectedEntityId`
- [ ] **Cluster selector buttons** — `setSelectedClusterId`
- [ ] **Artifact action panel buttons** — save / share / export
- [ ] **Chart bars** — presentational; driven by `chartProfiles[window]`

A full enumeration of buttons and per-region accessibility requires reading
lines beyond ~890 — flag for deeper walk.

## Data & contracts

- **Reads**: imports from `@oshun/domain-arete`: `buildAreteProgressMapExport`,
  `buildAreteCoachingSummaryShellModel`, `buildCanonicalAreteCoachingSummary`,
  `buildCanonicalAreteFrictionLog`, `buildCanonicalAreteGoal`,
  `buildCanonicalAreteHabit`, `buildCanonicalAreteReview`,
  `getAreteArtifactPolicy`, `summarizeAreteFrictionLogs`. Types:
  `AreteCanonicalCoachingSummary`, `AreteCanonicalGoal`, `AreteCanonicalHabit`,
  `AreteCanonicalReview`, `AreteFrictionLog`. In-file fixtures: `goals`,
  `habits`, `patternClusters`, `frictionLogs`, `chartProfiles`, `windowLabel`.
- **Writes**: `saveAreteArtifact` (localStorage); export triggers
  `triggerAreteArtifactDownload(buildAreteProgressMapExport({...}))`; no BFF
  write
- **Realtime**: none
- **Caching**: client bundle + localStorage
- **Auth/role check**: app-level middleware

## Cross-references

- Domain hub: [`arete.md`](./arete.md)
- Polished counterpart: [`arete-patterns.md`](./arete-patterns.md) — the static
  cross-section view
- Sibling internal alternates:
  - [`domains-arete-plan-review.md`](./domains-arete-plan-review.md)
  - [`domains-arete-journal.md`](./domains-arete-journal.md)
- Component source:
  `apps/oshun/web/src/components/domains/arete/AreteProgressMapsWorkspace.tsx`
- Library: `libs/domain-arete/*` (`@oshun/domain-arete`)
- Assistant dispatch: `apps/oshun/web/src/navigation/assistant-entry.ts`
- Artifact support:
  `apps/oshun/web/src/components/domains/arete/areteArtifactSupport.ts`,
  `AreteArtifactActionPanel.tsx`

## Open questions / known gaps

- [ ] No shared chrome with `/arete` polished surface
- [ ] Saved artifacts live in localStorage only; no server persistence
- [ ] Full per-region inventory requires reading source past line ~890; the
      bars, filters, cluster cards, and artifact panel need their own
      enumeration on a deeper walk
- [ ] How does this surface relate to the polished `/arete/patterns` — that one
      shows hour×day heatmap + correlations + mood; this one shows a
      momentum-bar chart + clusters + friction. Both are pattern-spotting, but
      render very differently. Document V1-shipping vs internal
