# Journey: Arete create habit

The cross-view flow from "user wants to add a new ritual" through "habit
created, first check-in recorded, streak begins, home rail reflects it." The
journey traverses both the polished Lilith room (`/arete`) and the deeper
internal habit-system surface (`/domains/arete/habits`), because the polished
hub's `+ New ritual` link is the natural starting point while the multi-step
creation flow lives in the internal namespace. Catches drift between the two
namespaces, the local-vs-server persistence boundary in the internal habit
system, and the streak-cannot-start case when the create-write never persists
across surfaces. The polished `/arete/habits/new` proposal lane is also covered
as the adjacent "held for coach review" path: its browser form fields are mapped
to the same real BFF habit contract, but the proposed habit does not start a
streak until coach review.

## Personas

- **First-habit user** — signed in with no Arete intentions; the BFF-backed room
  renders the explicit `data-arete-room-empty` state and points to the habits
  page
- **Adding-Nth-habit user** — already has 1–4 intentions; the polished
  `+ New ritual` button is the natural entry; the deeper habit-system surface
  exists at `/domains/arete/habits`
- **Coach-suggested user** — accepts or defers a Lilith coach-card proposal;
  both decisions persist through `/v1/arete/coach/decision`
- **Recovery-resuming user** — broken streak; new habit should not be punished
  by past quiet days (see
  [`customer/04-arete/arete-streak.md`](../customer/04-arete/arete-streak.md)
  promise copy)

## Pre-conditions

- Signed-in session
- `getArete()` reading `/v1/arete/room` into `AreteData` ({ intentions,
  weekStats, coachNote, eveningPrompt }); an unavailable feed returns an honest
  empty room rather than invented streak fixtures, per
  [`customer/04-arete/arete.md`](../customer/04-arete/arete.md)
- The internal `/domains/arete/habits` surface is reachable; client component
  imports `sampleHabits`, `sampleHabitStacks`, `sampleIdentityStatements`,
  `sampleHabitAnalytics` per
  [`customer/04-arete/domains-arete-habits.md`](../customer/04-arete/domains-arete-habits.md)
- Service worker active; offline behaviour deferred to
  [`shell/03-pwa-behavior.md`](../shell/03-pwa-behavior.md)

## Steps

### 1. Land on home and pick the Arete entry

- [ ] User on `/` after sign-in
- [ ] `HomeAretePracticeSection` rail visible with "Continue habit" / "See plan"
      affordances per
      [`customer/02-home-discovery/home.md`](../customer/02-home-discovery/home.md)
- [ ] `DomainCardGrid` shows the Arete domain card
- [ ] Click the Arete card → `/arete`
- [ ] Alternatively click "See plan" → `/arete/plan` (verify
      [`customer/04-arete/arete-plan.md`](../customer/04-arete/arete-plan.md)
      entry points), or use `g`-chord / shell-nav "Today" tab
- [ ] **Verify**:
      [`customer/02-home-discovery/home.md`](../customer/02-home-discovery/home.md)
      Arete practice section

### 2. Arete hub renders

`page.tsx` awaits `getArete()` → `<AreteRoom data={data} />`. The room mounts
`LCustomerNav active="today"` and `LSubNav active="habits"` with items Habits ·
Journal · Weekly review · Patterns.

- [ ] Page server-blocks on `getArete()` (no `loading.tsx` under `/arete`)
- [ ] Sub-nav highlights "Habits"
- [ ] Domain masthead reads "Arete · habits", display title "The small daily
      _rituals_."
- [ ] Existing intention rows, when present, render a "Done today" / "Pending"
      tag and seven-day cell bar; a fresh member instead sees the empty state
- [x] "+ New ritual" link is visible at the bottom of the intentions list and
      targets `/domains/arete/habits?wizard=loop`
- [ ] Coach card visible on the right with `data.coachNote`, "Approve" / "Not
      this week" buttons
- [ ] **Verify**: [`customer/04-arete/arete.md`](../customer/04-arete/arete.md)
      layout regions

### 3. Pick the create entry point

Three valid entry points; each lands the user in a different state.

- [x] **Entry A — `+ New ritual` button** on `/arete` — links to
      `/domains/arete/habits?wizard=loop`. Fixed 2026-06-23:
      `/domains/arete/habits/page.tsx` now reads `searchParams` and initializes
      `AreteHabitSystem` in `loop_wizard`, so the handoff lands in the wizard
      instead of dropping to the dashboard.
- [x] **Entry B — Coach card "Approve" / "Not this week"** — wired 2026-05-26
      via `AreteCoachActions` client component
      (`apps/oshun/web/src/components/lilith/AreteCoachActions.tsx`). Approve
      shows the "queued for the next review" confirmation; Not-this-week shows
      "Set aside for now". Both decisions POST `/v1/arete/coach/decision`, read
      back through `/v1/arete/room`, and can be undone to pending.
- [x] **Entry C — Each intention row's `↗` arrow** is now a `<Link>` to
      `/domains/arete/habits?habit=<label>` so the per-habit detail surface can
      read it. The polished `↗` was a static `<span>` until 2026-05-26.
- [x] **Entry D — `Propose a habit` on `/arete/habits`** — links to
      `/arete/habits/new`, verifies the label/cadence/domain/why form contract
      in the polished browser surface, then posts those same values through
      authenticated real HTTP to `POST /v1/arete/habits` and reloads
      `/arete/habits` to prove the server-rendered page reads the BFF habit
      back. This is intentionally a proposal path, not the immediate
      Cue→Routine→Reward active-habit wizard.

### 4. Enter the habit creation wizard (`HabitLoopWizard`)

Inside `/domains/arete/habits`, the dashboard exposes nine sub-views via the
`view` state union:
`dashboard | loop_wizard | four_laws | stacking | identity | keystone | streaks | analytics | reminders | detail`
per
[`customer/04-arete/domains-arete-habits.md`](../customer/04-arete/domains-arete-habits.md).

- [x] Tap the "New Habit" entry in `HabitDashboard`, or land via
      `/domains/arete/habits?wizard=loop`
- [x] State transitions: `view` flips from `dashboard` to `loop_wizard`;
      `<HabitLoopWizard onBack onCreate />` mounts
- [x] Wizard steps cover the shipped Atomic-Habits loop scaffolding: cue
      (`CueType`), routine description/duration/two-minute version, and reward
      (`RewardType`, immediate reward, long-term benefit)
- [x] Identity tie-in: from the same workspace, the final wizard step lists
      `sampleIdentityStatements`; the user can attach one identity statement to
      the new habit, the selected id is persisted in `useAreteStore`, and
      `IdentityPanel` reads it back under the matching identity per
      [`customer/04-arete/domains-arete-habits.md`](../customer/04-arete/domains-arete-habits.md).
- [ ] Confirm scope, ritual phrasing, frequency, reminder cadence
- [x] Back affordance: `onBack` returns to `view === 'dashboard'`
- [ ] **Verify**:
      [`customer/04-arete/domains-arete-habits.md`](../customer/04-arete/domains-arete-habits.md)
      view branches and `HabitLoopWizard` behaviour

### 5. Save the habit

Per
[`customer/04-arete/domains-arete-habits.md`](../customer/04-arete/domains-arete-habits.md)
the internal workspace now writes the same BFF habit-create contract that feeds
the polished `/arete` room, then mirrors the BFF id into the local store for the
same-browser dashboard/Home handoff.

- [x] Submit the wizard
- [x] Wizard builds a `HabitData` object from Cue/Routine/Reward, POSTs
      `/v1/arete/habits`, stores the returned `habitId` in the Arete Zustand
      store (`localStorage["oshun.arete"]`), closes, and returns to
      `view === 'dashboard'`. If an identity statement was selected, the
      outgoing `whyItMatters` summary includes it and the local habit also keeps
      `identityStatements: [identityId]`.
- [x] New habit row appears in `HabitDashboard`
- [x] Browser wizard POSTs to `/v1/arete/habits`; the polished `/arete` hub
      reads the same habit back through `/v1/arete/room`, including from a
      second browser context with no Arete localStorage seeded
- [x] The polished `/arete/habits/new` proposal form's browser field contract
      covers label, cadence, domain source, and rationale; Playwright uses the
      same values in an authenticated real `POST /v1/arete/habits`, verifies the
      held-for-review response, confirms authenticated `GET /v1/arete/habits`
      reads the proposed habit back with `streakDays: 0` and `todayKept: false`,
      and reloads `/arete/habits` to prove the page renders the live BFF row.
- [x] Telemetry: `arete_habit_created` fires after the browser wizard receives a
      successful BFF `habitId`, carrying the persisted id, label, cadence,
      source surface, cue type, duration, and identity-binding metadata.

### 6. Return to the polished `/arete` hub

The polished room and the internal habit system remain separate surfaces, but
the created habit now shares a BFF-backed source of truth.

- [x] Navigate to `/arete` via shell-nav "Today" or direct URL
- [x] Intention rows render — the just-created habit appears from
      `/v1/arete/room`
- [x] The row's detail link points back into `/domains/arete/habits?habit=...`
- [x] **Verify**: [`customer/04-arete/arete.md`](../customer/04-arete/arete.md)
      Data & contracts — `/arete` reads real member habits and week stats from
      `/v1/arete/room`

### 7. First check-in

- [x] On `/arete`, locate the new habit row read back through `/v1/arete/room`
- [x] In the polished hub, the `↗` action is a detail link to
      `/domains/arete/habits?habit=<label>`; it is not a check-in control. The
      check-in affordance therefore lives in the internal surface today
- [x] On `/domains/arete/habits` dashboard, tap the per-habit toggle for the
      wizard-created habit
- [x] The toggle POSTs `/v1/arete/habits/:habitId/check-in` with
      `status: "done"`, applies the BFF `streak.currentDays` / `completedToday`
      result to `useAreteStore`, and changes the dashboard toggle to the
      rest-day amend affordance
- [x] **Verify**:
      [`customer/04-arete/domains-arete-habits.md`](../customer/04-arete/domains-arete-habits.md)
      Interactions → "Per-habit toggle"

### 8. Streak begins

- [x] After the first check-in, the habit's streak transitions from 0 to 1 in
      the dashboard/local continuity store from the BFF response
- [x] Return to `/arete`; the intention row shows `Done today`, `1-day streak`,
      and the weekly KPI reads `1 / 7` completed across 1 ritual
- [x] Open `/arete` in a second browser context using the same real member
      session but no `oshun.arete` local continuity store; the intention row
      still shows `Done today`, `1-day streak`, and `1 / 7` via the fresh
      authenticated `/v1/arete/room` BFF read
- [x] Navigate to `/arete/streak` (direct URL; the per-view file
      [`customer/04-arete/arete-streak.md`](../customer/04-arete/arete-streak.md)
      flags that `/arete` intention rows show a streak eyebrow but no `href` is
      wired)
- [x] The phone-shell `AreteStreak` surface reads the live `/v1/arete/streak`
      rollup: a fresh member renders an honest `0 days`, and the real first
      check-in path reads back `1 day` on `/arete/streak`
- [x] The 42-cell heatmap on `/arete/streak` marks today's cell with `today`
      state (ink fill with 2px accent border) — the per-view file flags that
      today-state colour is `ink` with accent border
- [x] Promise copy "Two rest days a week are part of the practice" remains
      visible — humane recovery requirement per
      [`customer/04-arete/arete-streak.md`](../customer/04-arete/arete-streak.md)

### 9. Return to home and confirm rail update

- [x] Click shell-nav Home (or `g h`)
- [x] `HomeAretePracticeSection` rail now includes the new locally created habit
      as the active continuation commitment, even when the Arete Home BFF
      endpoint is unavailable
- [x] The primary continuation CTA targets the Arete habits lane (verify against
      [`customer/02-home-discovery/home.md`](../customer/02-home-discovery/home.md)
      Arete practice section)
- [x] After the first check-in, the live Home Arete rail reads the local
      continuity store back as `1d streak • done today`
- [x] `HomeFootingSummaryStrip` (`[data-kpi-grid]`) reflects the same local
      Arete check-in by adding the pending same-day completion to the live Home
      practice-streak metric; legacy `KpiGrid` remains preview-only per
      [`customer/02-home-discovery/home.md`](../customer/02-home-discovery/home.md)
- [ ] **Verify**:
      [`customer/02-home-discovery/home.md`](../customer/02-home-discovery/home.md)
      Arete practice section

### 10. Coach-card observation (lagged)

The Sunday letter on `/arete/coaching` proposes adjustments based on patterns
Lilith named. New habits should not trigger an adjustment until at least one
week of data is in.

- [ ] Navigate to `/arete/coaching` (direct URL — the per-view file
      [`customer/04-arete/arete-coaching.md`](../customer/04-arete/arete-coaching.md)
      flags that the coach card from `/arete` is not wired to here)
- [ ] The letter does not yet mention the new habit (week-old data requirement)
- [ ] On the next Sunday boundary, Lilith may surface an adjustment in the
      letter

## Post-conditions

- A new habit row exists in the BFF habit store, is mirrored into the local
  continuity store, and is visible on both the internal dashboard and polished
  Arete room
- Streak invariant: first check-in produces streak = 1 (not 0, not 2)
- Home `HomeAretePracticeSection` rail reflects the locally created habit as the
  current continuation commitment for the same browser profile
- No double-write: navigating between `/arete` and `/domains/arete/habits` and
  back does not create duplicate habits
- Telemetry: `arete_habit_created` is verified for the BFF-backed wizard create.
  The broader sequence remains candidate instrumentation: `arete_hub_viewed` →
  `arete_habit_create_started` → `arete_habit_checkin_first` →
  `arete_streak_started`

## Failure modes to verify

- [x] **Formerly inert "+ New ritual" control on `/arete`** — fixed 2026-05-26
      via `href="/domains/arete/habits?wizard=loop"` on the LBtn. If the link
      regresses, the polished room cannot start the create flow.
- [x] **Formerly inert coach-card decisions** — fixed 2026-05-26 via the
      `AreteCoachActions` client component (5-test suite). Decisions POST
      `/v1/arete/coach/decision` and read back through `/v1/arete/room`.
- [x] **Wizard Create was a no-op** — fixed 2026-06-23. `Create Habit` now
      builds a habit, POSTs it to `/v1/arete/habits`, persists the returned BFF
      id to `useAreteStore`, returns to the dashboard, renders the new row, and
      reads back on the polished `/arete` hub.
- [x] **Home rail ignores the wizard-created habit** — fixed 2026-06-23.
      `HomeAretePracticeSection` passes `useAreteStore.habits` into
      `buildHomeAretePracticeModel`; the model treats active local habits as
      Home commitments, promotes the newest local habit into the continuation
      card, and routes the primary CTA to the Arete habits lane. This is
      same-browser local read-back only, not a BFF/cross-device sync claim.
- [x] **First check-in stayed local-only for wizard-created habits** — fixed
      2026-06-23. Persisted wizard habits now POST
      `/v1/arete/habits/:habitId/check-in`, apply the BFF streak/today result to
      the dashboard and `useAreteStore`, read back as `Done today` /
      `1-day streak` / `1 / 7` on `/arete`, and surface `1d streak • done today`
      on the live Home Arete rail. The live Home footing strip also adds the
      pending same-day local Arete completion to its practice-streak metric
      while profile sync is still pending.
- [x] **Local-only sample-habit toggles in `/domains/arete/habits`** —
      `sampleHabits` check-ins mutate component state only because their fixture
      ids do not exist in the member's BFF habit store; Playwright now asserts
      the seeded toggle flips `aria-pressed`, restores on a second click, emits
      no `/v1/arete/habits/:habitId/check-in` POST, and creates no persisted
      local habit.
- [x] **Namespace drift between `/arete` and `/domains/arete/habits` for newly
      created habits** — fixed 2026-06-23. The wizard writes `/v1/arete/habits`
      and the polished room reads `/v1/arete/room`; seeded sample rows remain
      local to the internal workspace.
- [x] **Formerly inert `/arete/streak` "Adjust" and "Begin" controls** — both
      are wired as navigation links (`/arete/plan?intent=adjust` and
      `/tara/sit/when-the-mind-wanders`); no direct streak-mutation write exists
      on the streak surface
- [x] **`LSubNav` items lacked `href`** — fixed 2026-05-26. AreteRoom's sub-nav
      items now carry hrefs: Habits → `/domains/arete/habits`, Journal →
      `/domains/arete/journal`, Weekly review → `/arete/review`, Patterns →
      `/arete/patterns`.
- [ ] **No `loading.tsx` or `error.tsx` on `/arete`** — per-view file flags
      this; a failing `getArete()` falls through to the nearest ancestor
      boundary (or global error)
- [x] **Streak increment race for wizard-created habits** — fixed 2026-06-23.
      The persisted-habit toggle writes the BFF check-in first, then `/arete`
      reads the same check-in via `/v1/arete/room`. Seeded sample habits remain
      internal-only and are not represented on `/arete`.
- [x] **Polished proposal form field contract was not tied to the real BFF habit
      contract** — fixed 2026-06-27. `/arete/habits` → `Propose a habit` now has
      Playwright coverage that drives `/arete/habits/new`, verifies the browser
      field semantics, posts the same payload through authenticated real HTTP,
      reads the proposed habit back through authenticated
      `GET /v1/arete/habits`, and reloads the browser page to prove live
      server-rendered read-back.

## E2E coverage

- [`apps/oshun/web/e2e/arete-create-habit.spec.ts`](../../apps/oshun/web/e2e/arete-create-habit.spec.ts)
  — the habit dashboard `/domains/arete/habits` (the HabitLoopWizard opens via
  "New Habit" and Back returns to the dashboard;
  `/domains/arete/habits?wizard=loop` lands directly in the wizard;
  Cue→Routine→Reward POSTs the real BFF habit-create route, persists the
  returned BFF habit id locally, emits browser telemetry event
  `arete_habit_created` with the persisted habit id and habit-loop metadata,
  renders the new row, persists a selected `sampleIdentityStatements` id
  locally, asserts the outgoing BFF `whyItMatters` identity line, and reads the
  created habit back in `IdentityPanel`, POSTs the first check-in to
  `/v1/arete/habits/:habitId/check-in`, applies the returned streak locally,
  reads back `Done today` / `1-day streak` / `1 / 7` on polished `/arete`, opens
  a second browser context with the same real member session and no
  `oshun.arete` local store to prove `/arete` rehydrates the checked-in habit
  from `/v1/arete/room`, reads back `1d streak • done today` on Home Arete, and
  reads the checked-in habit's live overall rollup back on `/arete/streak` as
  `1 day`; the same return-to-Home path asserts `HomeFootingSummaryStrip`
  (`[data-kpi-grid]`) increments the practice-streak metric from the browser's
  current profile streak plus the pending local Arete check-in; **the seeded
  per-habit toggle is still driven as a fixture-only boundary — a click inverts
  its `aria-pressed` state, a second click restores it, no BFF check-in POST
  leaves the browser, and no persisted local habit is created**); the polished
  `/arete/habits` proposal lane (`Propose a habit` → `/arete/habits/new` field
  contract → same payload real BFF POST → authenticated BFF GET read-back with
  zero streak/no kept-today state → browser `/arete/habits` live row read-back);
  and the `/arete/streak` surface (no-punish promise copy, live zero-streak
  count + gently-kept lede for a fresh member, 42-cell six-week heatmap with one
  accessible `today` marker at cell 41, legend, and the wired
  `Adjust`→`/arete/plan?intent=adjust` /
  `Begin`→`/tara/sit/when-the-mind-wanders` resumption affordances).
- [`apps/oshun/web/e2e/arete-full-journey.spec.ts`](../../apps/oshun/web/e2e/arete-full-journey.spec.ts)
  — drives the older broad Arete path, including the controlled
  accepted-response "held for coach review" acknowledgement plus coach Approve /
  "Not this week" decision + undo. The proposal form's real-BFF read-back now
  lives in `arete-create-habit.spec.ts`.
- [`apps/oshun/web/e2e/arete-habits-bff.spec.ts`](../../apps/oshun/web/e2e/arete-habits-bff.spec.ts)
  — the genuine server habit-create engine, over **real HTTP** against the
  running BFF: `POST /v1/arete/habits` persistence + GET round-trip, and the
  `422 habit_label_too_short` validation rejection. The same spec now proves the
  live check-in loop and guardrails: create/check-in 401 auth gates, invalid
  check-in status 422, owner-only check-in with non-enumerating 404 for another
  member, no-store mutation responses, durable `done` read-back into
  `todayKept`/`streakDays`, and same-day amendment to an explicit rest day
  (`skip` → `grace`) with the list returning to `todayKept: false`.
- **Coverage depth**: partial — see [`coverage.md`](./coverage.md).
- **Uncovered**: cross-device check-in sync is now covered for the polished
  `/arete` BFF read model, and `/arete/streak` now reads the live
  `/v1/arete/streak` rollup for both fresh-zero and first-check-in states.
  Home's Arete continuation remains intentionally same-browser local continuity,
  and legacy `KpiGrid` habits-this-week coverage is not asserted because
  `KpiGrid` is not part of the live Home surface. Remaining partial-depth items
  are the older manual checklist gaps for reminder-cadence/scope confirmation,
  lagged Sunday coaching observation, and the `/arete` missing `loading.tsx` /
  `error.tsx` boundary. The polished-hub intention rows are also exercised by
  `arete-full-journey.spec.ts`.

## Per-view files touched by this journey

- [`customer/02-home-discovery/home.md`](../customer/02-home-discovery/home.md)
  — Arete practice rail entry and return point
- [`customer/04-arete/arete.md`](../customer/04-arete/arete.md) — polished
  Lilith room, `+ New ritual` link, coach card
- [`customer/04-arete/arete-plan.md`](../customer/04-arete/arete-plan.md) — "See
  plan" link from home rail
- [`customer/04-arete/arete-streak.md`](../customer/04-arete/arete-streak.md) —
  streak surface after first check-in
- [`customer/04-arete/arete-goal.md`](../customer/04-arete/arete-goal.md) —
  goal-to-habit binding (habit "feeds" a goal)
- [`customer/04-arete/arete-coaching.md`](../customer/04-arete/arete-coaching.md)
  — lagged coach feedback on the new habit
- [`customer/04-arete/domains-arete-habits.md`](../customer/04-arete/domains-arete-habits.md)
  — `AreteHabitSystem`, `HabitLoopWizard`, identity statements
- [`customer/04-arete/domains-arete-journal.md`](../customer/04-arete/domains-arete-journal.md)
  — optional habit-related journal entry after check-in

## Cross-references

- Feature spec: [`V1/features.md#arete`](../../V1/features.md#arete)
- Architecture:
  [`V1/ARCHITECTURE.md#customer-web--appsoshunweb`](../../V1/ARCHITECTURE.md#customer-web--appsoshunweb)
- Related journeys:
  - [`tara-daily-ritual.md`](./tara-daily-ritual.md) — streak interplay with
    Tara sit completion
  - [`install-as-pwa.md`](./install-as-pwa.md) — relaunch target may include
    `/arete/streak`
- Shell:
  - [`shell/01-app-shell.md`](../shell/01-app-shell.md)
  - [`shell/04-auth-session.md`](../shell/04-auth-session.md)
  - [`shell/06-keyboard-a11y.md`](../shell/06-keyboard-a11y.md)
- Component sources:
  - `apps/oshun/web/src/app/arete/page.tsx` — polished hub entry
  - `apps/oshun/web/src/components/lilith/rooms.tsx` — `AreteRoom`
  - `apps/oshun/web/src/components/lilith/arete.tsx` — `AretePlan`,
    `AreteStreak`, `AreteGoal`, `AreteCoaching`
  - `apps/oshun/web/src/components/domains/arete/AreteHabitSystem.tsx` —
    internal workspace + nine subviews
  - `apps/oshun/web/src/lib/lilith-data/arete.ts` — `getArete()`
  - `apps/oshun/web/src/lib/arete/arete-simulation-data.ts` — `sampleHabits`
  - `apps/oshun/web/src/lib/arete/arete-types.ts` — `HabitData`,
    `IdentityStatement`, `CueType`, `RewardType`, etc.

## Open questions / known gaps

- [x] Confirm whether `/arete` and `/domains/arete/habits` share a store in V1
      for created habits — the wizard POSTs `/v1/arete/habits` and `/arete`
      reads back through `/v1/arete/room`; internal sample rows remain local
- [x] Connect the browser `HabitLoopWizard` to the actual habit-create endpoint
      (`POST /v1/arete/habits`)
- [x] Document whether the internal namespace's local-store wizard is meant to
      graduate into the polished `/arete/habits/new` BFF-backed create flow: it
      now shares the same BFF create route while retaining the richer local
      Cue/Routine/Reward metadata for same-browser Home continuity
- [x] Wire coach-card Approve / Not this week decisions to the BFF — decisions
      POST `/v1/arete/coach/decision` and read back through `/v1/arete/room`
- [x] Confirm whether the streak increment is a synchronous client mutation or a
      BFF round-trip — persisted wizard habits POST
      `/v1/arete/habits/:habitId/check-in`; seeded sample rows remain local-only
- [x] Document the identity-statement → habit binding contract: a wizard-created
      habit may attach one `IdentityStatement` id from
      `sampleIdentityStatements`; the selected statement is included in the BFF
      `whyItMatters` summary, and the id is stored in the local Arete continuity
      store and shown by `IdentityPanel`. The current BFF habit route does not
      expose a first-class identity column.
