# Journey: Nisaba scholarly read

This journey has three visible passage identities, not one continuous record:

1. Search opens **On Guarded Speech**, Epictetus, _Enchiridion_ XXXIII in the
   interactive `/domains/nisaba` workspace.
2. The compact `/nisaba` room independently resolves the account's daily
   passage, **Mind Precedes All States**, Dhammapada I.1–2. Its annotation count
   uses that same passage, while its footer actions still use the separate id
   `nisaba-on-the-ruling-part`.
3. `/nisaba/scholar`, `/lexicon`, `/manuscript`, `/notebook`, and `/plan` switch
   to static Marcus Aurelius / **On the ruling part** fixtures.

A reader can do substantive work in the live workspace today. Moving among all
of these routes, however, does not prove that one passage, annotation, notebook,
or plan followed them.

## Personas

- **Reader** — searches for a primary text and reads the returned passage.
- **Annotator** — creates or updates an owner-scoped annotation in the live
  domain workspace.
- **Study planner** — uses live notebook APIs where available and distinguishes
  them from browser-local notes, collections, and plans.
- **Offline reader** — revisits a warm, eligible daily-passage or notebook-list
  response on the same browser.

## Pre-conditions

- Use an authenticated session with an `oshun-access` cookie. Server components
  forward that value as the BFF bearer; client requests need their own in-memory
  API token.
- Choose the surface deliberately:
  - `/domains/nisaba?path=...` is the parameterized interactive workspace.
  - `/nisaba` is the compact daily-passage room.
  - the five legacy depth pages read `nisaba-depth.ts` fixtures. In short, the
    legacy depth pages read fixtures rather than the selected live passage.
- Do not infer a shared passage from visual continuity or the Nisaba masthead.
- Fetch offline-eligible content once while online. There is no whole-workspace
  download. There is no **Keep offline** action.

## Steps

### 1. Search for a Nisaba passage

Open `/search?q=ruling+part` and select the Nisaba passage result. The search
seed carries `nisaba-passage-speech` and
`/library/passage/nisaba-passage-speech`; the shell launcher encodes that path
under `/domains/nisaba`.

In the named Playwright harness, search is an assisted seam: the client has no
in-memory token, so the spec reissues the intercepted GET to the real BFF with a
generated dev bearer and forwards the real response. Treat this as real ranking
and launch evidence, not proof that the browser acquired search auth by itself.

### 2. Verify the live passage identity

The domain workspace should resolve **On Guarded Speech**, **Enchiridion
XXXIII**, and the attributed Epictetus source. This path fetches the requested
passage detail instead of falling back to the daily passage when the response id
matches.

The workspace exposes annotation, notebook, compare, collection, study-plan,
citation, lexicon, timeline, and scholar affordances. Presence is not a write.
When the task requires persistence, operate the relevant control and verify the
same passage and record through its BFF read-back.

### 3. Treat `/nisaba` as a separate compact room

Open `/nisaba` only when the daily room is intended. The server component
requests `/v1/nisaba/room`; an unreachable or malformed response becomes an
explicit unavailable page. An authorized response contains the current daily
passage's title, citation, body, available language, related concepts, and
comparison targets. The seeded account currently resolves **Mind Precedes All
States**, Dhammapada I.1–2.

The route queries annotations for that same daily passage before building the
room, so its **Annotations** count is identity-aligned. **Cross-references: 4**
and **Saved excerpts: 2** remain authored constants rather than derived totals.

### 4. Use language and section controls as presentation controls

The room exposes only the language carried by the daily passage record; the
seeded passage is English, so it no longer invents Pali or side-by-side text.
The footer's section links still update the URL hash even though a dynamic daily
passage has no authored section apparatus. Neither operation changes a canonical
passage record or persists a reading position.

The room's footer Save, Read aloud, and Flag controls currently receive
`nisaba-on-the-ruling-part`, not the daily passage id. Do not rely on the saved
resume path or flag target as a canonical identity for the visible room.

### 5. Annotate and verify through the live workspace

Return to `/domains/nisaba?path=/library/passage/<id>` for a real annotation.
Create or edit it, then reload or call the owner-scoped read endpoint and verify
the same passage id and annotation id. If notebook association matters, verify
the synchronized notebook item as described by the notebook-capture journey.

The named `nisaba-scholarly-read.spec.ts` does not perform that mutation. Its
twelve live reading-action selectors establish discoverability, not completion.

### 6. Use the legacy scholar page as a specimen

`/nisaba/scholar` shows Marcus Aurelius, _Meditations_ IV.viii–xii, four
witnesses, cross-reference groups, marginalia, and concepts from a fixture.
**Reader mode**, **Edition: Farquharson 1944**, and **Cite** render as buttons
but have no handler or destination.

Browser Back returns to the compact room. That is navigation-history evidence,
not a passage or edition handoff.

### 7. Inspect legacy lexicon and manuscript anatomy

`/nisaba/lexicon` renders the Greek headword, morphology, glosses, and
attestations. Its neighboring-word arrows are text rather than links.
`/nisaba/manuscript` renders an authored folio/codex specimen. Neither is
selected from the Epictetus workspace or daily Dhammapada room.

### 8. Distinguish the fixture notebook from live notebooks

`/nisaba/notebook` always renders Renata K.'s **On the ruling part** composition
from a zero-argument fixture. It has no editable field or save control. Its
`noindex, nofollow` metadata is crawler policy, not an account or ownership
check.

Use live BFF notebook routes or the interactive domain workspace when a durable
member notebook is required. Browser-local study notes are another authority and
disappear when their site storage is cleared.

### 9. Distinguish the fixture plan from a created study plan

`/nisaba/plan` always renders the authored seven-week arc at week four, 18 of 31
readings. It has no add, complete, or mark control and does not derive from the
search result, compact room, or fixture notebook. Use the live workspace's plan
tools for a browser-local plan, then label it local unless a server write is
separately proven.

### 10. Revisit only eligible warm content offline

The client stores 24-hour snapshots for the daily passage and notebook lists.
The service worker separately caches only `/v1/nisaba/passages/daily` and
`/v1/nisaba/notebooks` under the same 24-hour policy. Requested passage detail,
room, annotation, manuscript, and legacy depth responses are not in that API
allowlist.

The cache and snapshot keys are URL/status scoped rather than member scoped.
Normal session clear purges member caches, so verify that cleanup on shared-
device privacy tests instead of treating a warm response as intrinsically
subject-partitioned.

## Post-conditions

- The selected passage id and title are recorded for every live write.
- A BFF annotation or notebook item is verified through owner-scoped read-back
  when persistence was part of the task.
- Browser-local notes, collections, and plans remain labelled local.
- Compact-room counts are tied to the daily passage; its action id is not.
- Legacy pages are recorded as fixtures, not continuity evidence.
- Offline claims identify the exact warm endpoint, age limit, browser, and
  session-cleanup dependency.

## Failure modes

- **Assisted search mistaken for native auth** — the test forwards a real BFF
  response using its own dev bearer because the search client token is null.
- **Surface mismatch** — a reader expects the search-selected passage on the
  compact or legacy routes.
- **Save identity mismatch** — the compact room's visible title is stored under
  `nisaba-on-the-ruling-part`.
- **Static control mistaken for an action** — a Scholar toolbar, lexicon arrow,
  fixture notebook, or fixture plan changes no durable state.
- **Robots metadata mistaken for privacy** — no-index metadata does not enforce
  ownership.
- **Local state mistaken for durable state** — clearing localStorage removes
  study notes, drafts, collections, plans, and offline snapshots.
- **Cold or expired offline request** — the endpoint was never warmed, falls
  outside the allowlist, or its cached response is older than 24 hours.
- **Session cleanup omitted** — a URL-keyed authenticated response remains a
  shared-browser privacy concern until member caches are purged.

## E2E coverage

- [`apps/oshun/web/e2e/nisaba-scholarly-read.spec.ts`](../../apps/oshun/web/e2e/nisaba-scholarly-read.spec.ts)
  has 11 cases for assisted real search, parameterized live-workspace anatomy,
  compact-room anatomy/language/hash navigation, five legacy specimens, and
  browser Back.
- [`apps/oshun/web/e2e/nisaba-desk-deepening.spec.ts`](../../apps/oshun/web/e2e/nisaba-desk-deepening.spec.ts)
  has five real-HTTP cases for missing, invalid, wrong-scope, `domain:nisaba`,
  and `domain:*` room requests. Its introductory claim that server rendering
  cannot forward a bearer is stale; `bff-fetch.ts` now forwards `oshun-access`.
- [`apps/oshun/web/e2e/nisaba-annotation-bff.spec.ts`](../../apps/oshun/web/e2e/nisaba-annotation-bff.spec.ts)
  and
  [`apps/oshun/web/e2e/nisaba-notebook-bff.spec.ts`](../../apps/oshun/web/e2e/nisaba-notebook-bff.spec.ts)
  prove adjacent owner-scoped APIs, not the named end-to-end scholarly chain.
- [`apps/oshun/web/e2e/nisaba-reading-compare-annotate.spec.ts`](../../apps/oshun/web/e2e/nisaba-reading-compare-annotate.spec.ts)
  and
  [`apps/oshun/web/e2e/nisaba-split-view.spec.ts`](../../apps/oshun/web/e2e/nisaba-split-view.spec.ts)
  exercise deeper live-workspace interactions under their own fixtures and
  assertions.
- Coverage remains **partial** for one joined search → passage → annotation →
  notebook → plan → reload record.

## Per-view files touched

- [`customer/07-nisaba/nisaba.md`](../customer/07-nisaba/nisaba.md) — compact
  room.
- [`customer/07-nisaba/nisaba-scholar.md`](../customer/07-nisaba/nisaba-scholar.md)
  — legacy Scholar specimen.
- [`customer/07-nisaba/nisaba-notebook.md`](../customer/07-nisaba/nisaba-notebook.md)
  — legacy notebook specimen.
- [`customer/07-nisaba/nisaba-plan.md`](../customer/07-nisaba/nisaba-plan.md) —
  legacy plan specimen.
- [`customer/07-nisaba/nisaba-compare.md`](../customer/07-nisaba/nisaba-compare.md)
  — one live domain-workspace path.

## Cross-references

- [`nisaba-notebook-capture-and-cite.md`](./nisaba-notebook-capture-and-cite.md)
  — durable notebook, synchronized annotation-item, local-note, citation, and
  fixture boundaries.
- [`search-explore-deep-read-library-save.md`](./search-explore-deep-read-library-save.md)
  — search launch and Library-save semantics.
- [`offline-first-time-use.md`](./offline-first-time-use.md) — service-worker
  scope, warm-cache semantics, and cleanup.
- Code: `apps/oshun/web/src/components/domains/NisabaSurface.tsx`,
  `apps/oshun/bff/src/nisaba/room.ts`,
  `apps/oshun/web/src/lib/nisaba-offline.ts`, and `apps/oshun/web/public/sw.js`.

## Open questions

- Should compact and live surfaces resolve one canonical passage id?
- Should the compact room return its canonical passage id and pass it to Save,
  Read aloud, and Flag?
- Should legacy depth routes be live, retired, or visibly labelled specimens?
- Which notes and plans should become durable, cross-device records?
- Should offline caches and snapshots be explicitly subject-partitioned?
