Journey flow#
Generated from the authored steps below — click a node to jump to that section.
This journey has three visible passage identities, not one continuous record:
- Search opens On Guarded Speech, Epictetus, Enchiridion XXXIII in the
interactive
/domains/nisabaworkspace. - The compact
/nisabaroom 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 idnisaba-on-the-ruling-part. /nisaba/scholar,/lexicon,/manuscript,/notebook, and/planswitch 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-accesscookie. 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./nisabais the compact daily-passage room.- the five legacy depth pages read
nisaba-depth.tsfixtures. 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.tshas 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.tshas five real-HTTP cases for missing, invalid, wrong-scope,domain:nisaba, anddomain:*room requests. Its introductory claim that server rendering cannot forward a bearer is stale;bff-fetch.tsnow forwardsoshun-access.apps/oshun/web/e2e/nisaba-annotation-bff.spec.tsandapps/oshun/web/e2e/nisaba-notebook-bff.spec.tsprove adjacent owner-scoped APIs, not the named end-to-end scholarly chain.apps/oshun/web/e2e/nisaba-reading-compare-annotate.spec.tsandapps/oshun/web/e2e/nisaba-split-view.spec.tsexercise 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— compact room.customer/07-nisaba/nisaba-scholar.md— legacy Scholar specimen.customer/07-nisaba/nisaba-notebook.md— legacy notebook specimen.customer/07-nisaba/nisaba-plan.md— legacy plan specimen.customer/07-nisaba/nisaba-compare.md— one live domain-workspace path.
Cross-references#
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 launch and Library-save semantics.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, andapps/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?