# Conventions

How to read, write, and update the files in this folder.

## Per-view file template

Every route gets a file. Every file follows this template exactly. Sections may
be empty (write `_None._`) but must be present, so a reader knows what they're
looking at.

````markdown
---
path: /exact/route/pattern
surface: customer | studio | operator | workspace
domain: <the controlled domain slug used by the matching routes.csv row>
auth: anon | signed-in | signed-in + role:<role> | signed-in + tenant:<tenant>
source: apps/oshun/web/src/app/<path>/page.tsx
status: stub | drafted | walked | stale
last_walked: 'YYYY-MM-DD by <walker/method>, against commit <sha>'
---

# <Human-readable view name>

## Purpose

One paragraph (≤ 3 sentences). What is this view for, and who uses it. Avoid
restating what's already in `V1/features.md` — link to the relevant anchor
instead.

## Entry points

How a user arrives at this view.

- Linked from `<route>` via `<link element / button label>`
- Deep link from `<email / push / SMS / share target>`
- Search result from `/search` for query `<example>`
- Direct URL (bookmarkable / shareable / role-gated / hidden)
- Shell nav (home / explore / activity / library / profile / domain switcher)

## Layout regions

The named visual regions a user can identify, top to bottom (or left-to-right on
wide breakpoints). Use the actual region names from the page component.

- **Header**: <variant — shell header / domain header / minimal>
- **Hero / above-the-fold**: <what's here>
- **Main**: <primary content panel>
- **Aside / secondary panel**: <if any>
- **Footer / sticky bottom**: <if any>

## States

Every observable visual state of the view. Produce it in local development when
the required system is available; otherwise mark it N/A with a reason or leave
it unchecked with the exact external prerequisite. Never invent reachability.

- [ ] **Loading** — skeleton or spinner matches final layout dimensions (no
      CLS); skeleton respects theme tokens; loading attribute announced to
      screen readers
- [ ] **Empty** — no data; on-brand copy; CTA points to a productive next
      action; not just a "nothing here" placeholder
- [ ] **Populated (short)** — 1–5 items; expected layout
- [ ] **Populated (long)** — 50+ items; pagination/virtualization/infinite
      scroll works; scroll position restored on back-navigation
- [ ] **Error (recoverable)** — failed query; retry button works; original query
      parameters preserved
- [ ] **Error (unrecoverable)** — 500/403; support contact link; navigation away
      still works
- [ ] **Offline** — network unreachable; SW serves cached read where sensible;
      writes are queued or disabled with explanation; offline banner visible
- [ ] **Gated** — auth/role/feature-flag denies; user sees why and how to
      unlock; no information leak
- [ ] **Standalone PWA** — view renders cleanly when launched from home-screen
      icon; URL bar absent; safe-area insets respected

If a state cannot occur for this view, write
`- [x] **<state>** — N/A because <reason>` so the omission is auditable.

## Interactions

One bullet per discrete interactive element. Drill into nested elements (e.g., a
menu's items, a modal's buttons).

Each bullet uses this micro-template:

```
- [ ] **<Element label>** (<element type: button / input / link / tab / etc.>)
  - Function: <what it does>
  - Keyboard: <key activates; tab order position>
  - Screen reader: announces "<text>"
  - Touch target: ≥ 44×44 CSS px on coarse pointers
  - Mobile (≤ 640 px): <any layout/behavior delta>
  - Disabled when: <condition> → tooltip/aria-disabled text "<text>"
  - Offline behavior: <queue / disable / no-op>
  - Telemetry: <event name fired>
```

If a sub-element exists (e.g., menu items, dialog content), nest its bullets one
level deeper.

## Data & contracts

What this view reads, writes, and subscribes to.

- **Reads**: `<BFF route or lib call>` — returns `<contract type>`
- **Writes**: `<BFF route>` — accepts `<contract type>`
- **Realtime**: `<channel/topic if any>` — `<events handled>`
- **Caching**: SSR / SWR / ISR / static / SW-cached (which cache key)
- **Auth/role check**: `<middleware.ts rule or BFF policy>`

Link to the contract in `libs/contracts/` or `libs/openapi/`.

## Cross-references

- Feature spec: [`V1/features.md#<anchor>`](../V1/features.md#anchor)
- Architecture: [`V1/ARCHITECTURE.md#<anchor>`](../V1/ARCHITECTURE.md#anchor)
- Journeys that pass through this view: `journeys/<file>.md`
- Sibling routes: `<list>`
- Component sources: `apps/oshun/web/src/<dir>/<file>.tsx`

## Open questions / known gaps

- [ ] <items the walker noted but couldn't resolve in one pass>
````

## Status legend

| Status  | Meaning                                                                                                         |
| ------- | --------------------------------------------------------------------------------------------------------------- |
| stub    | File exists with header; content not written.                                                                   |
| drafted | Content written from code reading; not yet verified against a running app.                                      |
| walked  | Direct runtime evidence (manual or automated) verifies every reachable check; the method and date are recorded. |
| stale   | The file is walked but the code under `source` has changed since `last_walked`.                                 |

Status is the truth in `matrix/routes.csv`. The status header inside each file
mirrors the CSV. When you walk a view, update **both**.

## Cross-reference rules

- A bare `§N` or `§N.M` resolves to `V1/TODOS.md` (the execution backlog).
- `features§"<anchor>"` resolves to `V1/features.md` by heading anchor.
- `arch§"<anchor>"` resolves to `V1/ARCHITECTURE.md` by heading anchor.
- Within the walkthrough, link with relative Markdown paths (for example,
  `[PWA behavior](./shell/03-pwa-behavior.md)`).

## E2E test coverage (specs ↔ journeys)

Journeys are executable targets. Automation-backed journeys link one or more
Playwright specs under `apps/oshun/web/e2e/`; journeys without meaningful
automation are labelled as manual in the Docs Center registry. Where a spec
exists, the link is **bidirectional and mechanically checkable** so a reviewer
can jump from a flow to the test that guards it and back, and drift between the
two is visible.

**1. Spec → journey (header comment).** Every spec that covers a journey opens
with a fenced header block naming the journey doc and the steps it exercises:

```ts
/**
 * E2E · Journey: WALKTHROUGH/journeys/<journey-name>.md
 * Covers: steps 1–6 (proxy boundary 307/404 → /aaa-upgrade page → AaaGate embed leak).
 * Coverage matrix: WALKTHROUGH/journeys/coverage.md
 *
 * A spec may cover one journey, part of a journey, or steps shared by several
 * journeys — list each journey it backs on its own `Journey:` line.
 */
```

The `Journey:` line uses the repo-relative path (greppable, unambiguous). A spec
that is purely per-view (not tied to a journey) omits the block — only
journey-backing specs carry it.

**2. Journey → spec (`## E2E coverage` section).** Every journey doc carries an
`## E2E coverage` section, placed immediately after **Failure modes** and before
**Per-view files touched**:

```markdown
## E2E coverage

- [`apps/oshun/web/e2e/<file>.spec.ts`](../../apps/oshun/web/e2e/<file>.spec.ts)
  — steps 1–6; drives the proxy boundary, the disclosure page, and the embed
  gate.
- **Coverage depth**: deep | partial | shallow | none — see
  [`coverage.md`](./coverage.md).
- **Uncovered**: list any step/failure-mode no spec exercises yet, with the
  reason (blocked on a missing route, requires a testnet, etc.). `_None._` when
  whole.
```

**3. Master matrix.** [`journeys/coverage.md`](./journeys/coverage.md) is the
single index: every journey → its primary spec(s) → coverage depth → status. It
is the source of truth for "is this flow tested, and how well". Update it in the
same change that adds or deepens a spec.

**Coverage-depth rubric** (used in the matrix and the per-journey section):

| Depth       | Meaning                                                                                                                         |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------- |
| **deep**    | Drives the journey's interactions (click/type/nav), asserts state transitions + post-conditions, and exercises ≥1 failure mode. |
| **partial** | Exercises some steps but skips key interactions, failure modes, or post-conditions.                                             |
| **shallow** | Smoke only — asserts a heading/URL renders; does not drive the journey's interactions.                                          |
| **none**    | No spec meaningfully covers the journey.                                                                                        |

A shallow spec is the test-equivalent of a stub: it would pass against an almost
empty page. Treat `shallow` like `stub` in the route matrix — it is not done.

## Check authoring rules

- **One element, one bullet.** A "save and continue" button is one bullet, not
  two — but if the bullet's behavior depends on which mode the form is in, the
  bullet says so.
- **Verbs, not descriptions.** `- [ ] **Save** opens confirmation` — not
  `- [ ] There is a confirmation`.
- **Per-state, not per-pixel.** Don't itemize visual styling unless the spec
  calls out a specific token or animation.
- **No hypotheticals.** Only list elements that exist in code today. If the spec
  says something must exist and the code doesn't have it, log it under "Open
  questions / known gaps".
- **Use the actual label / placeholder / aria-label text** so a reader can use
  Ctrl+F in the running app to find the element.

## Walking discipline

Walking a file means:

1. Open the per-view file. Read `source:`.
2. Open `apps/oshun/web/src/app/<route>/page.tsx`. Make sure the file exists and
   the imports are recognizable.
3. Run the app locally. Navigate to the route as the auth role specified in the
   header.
4. For each state in **States**: produce that state in the running app (use dev
   tools / mock data / network throttling / role switcher) and tick the box.
5. For each bullet in **Interactions**: trigger it; verify function, keyboard,
   screen reader, touch target, mobile, disabled, offline, and telemetry. Tick
   when all sub-bullets pass.
6. Verify **Data & contracts** by tracing a network request in DevTools.
7. Update `status: walked` and
   `last_walked: <date> by <name>, against commit <sha>` in the file header.
   Update the matching CSV row.

If you can't reach a state or trigger an interaction, leave it unchecked and
write what blocked you in **Open questions / known gaps**. Never tick a box you
didn't verify.

## File naming

Files within a folder use kebab-case derived from the route, with the leading
slash stripped:

| Route                     | File                                         |
| ------------------------- | -------------------------------------------- |
| `/`                       | `customer/02-home-discovery/home.md`         |
| `/tara`                   | `customer/03-tara/tara.md`                   |
| `/arete/coaching`         | `customer/04-arete/arete-coaching.md`        |
| `/domains/arete/journal`  | `customer/04-arete/domains-arete-journal.md` |
| `/studio/design-language` | `studio/design/studio-design-language.md`    |
| `/operator/review-queues` | `operator/operator-review-queues.md`         |

A file named `README.md` inside a domain folder is the domain index — it lists
every route in that folder with one-line status and a link.
