V1 Web PWA · Walk result

Journey result: Nisaba notebook capture and cite — two durable lanes, disconnected clients

A dated evidence record for V1 Web PWA: observed behavior, current source reconciliation, automation evidence, and explicit proof limits.

verdict: partial· 2026-05-29
8sections26 minread1table

On this page
  • Walked: 2026-05-29 at 9455bc53ad. The retained result named an ephemeral /tmp/claude-oshun-lt-2-walkthrough/walk.mjs script and recorded three rendered routes, one notebook create request, zero page errors, and zero persistent failures. It preserved no script, trace, account, notebook id, annotation, item read-back, citation payload, or downloaded artifact.
  • Reconciled: 2026-07-21 against the notebook index and create form, live Nisaba reading workspace, browser note and citation builders, fixture notebook detail and export block, authenticated BFF routes, ordered durable store, production wiring, erasure/export integration, the now-interactive Studio study workspace, its session-verifying proxy, Yemaya study service, Nisaba-owned Postgres adapter, publication gate, study-trail export, four Studio browser suites, three BFF durability suites, and all nine legacy Playwright files. This was source review, not a fresh application, BFF, study-service, Postgres, object-store, or product-browser run.
  • Verdict: partial / deep for the independent shipped seams — owner- scoped notebooks and annotations have real HTTP contracts, write-before-ack durable snapshots, restart restoration, deletion fences, and data export. Annotation-to-notebook association also materializes a real notebook item. Studio now delivers a second durable, anchor-cited path with Nisaba-native notebook/card identities and a study-trail export. The legacy browser still does not join its create label, local study-note composer, stored-notebook links, citation generator, and fixture export page to that path or to one canonical citation lifecycle.
  • Current authority: WALKTHROUGH/journeys/nisaba-notebook-capture-and-cite.md follows the split between the legacy BFF snapshot, the Studio study service's Nisaba Postgres records, browser-local study notes, client-derived citations, and the authored notebook specimen.

Result at a glance#

Interaction Proof · limit
Historical route walk Proof: /nisaba, /nisaba/notebooks, and /nisaba/notebook/new rendered, and the create form reached POST /v1/nisaba/notebooks. Limit: route reachability and a request attempt did not prove owner read-back, item capture, durable commit, citation provenance, or that the opened detail represented the created id.
Studio study workspace Proof: /studio/study now mounts a real project → rights → ingest → anchor → notebook/card → study-trail-export client behind a session-verifying web proxy. Four available capability entries point to the live workspace, Nisaba index, and Library; ten craft lenses are explicitly manual-only, and automated analysis is unavailable. Limit: this is a separate study-service/Nisaba-Postgres authority, not hydration of the legacy BFF notebook pages, local notes, or six-format citation builder.
Studio notebook and card Proof: the service rejects unknown anchors, mints nbk_/crd_ identities in Nisaba-owned code, stores current revisions in nisaba_study, gates audience widening by cited-work rights, restores across an app restart, and includes notebooks in a rights-filtered study-trail export. Limit: the UI always cites its first anchor; notebook creation and project-ref update span two databases without a transaction; card insert and notebook supersession are also separate statements; the card route does not authorize the target notebook.
Notebook creation Proof: the mobile browser case submits title, visibility, and optional text with bearer and CSRF headers, receives a generated notebook id, and reads the row back from the real BFF. Limit: the field labelled First passage (optional) is converted to summary; the form sends no linkedPassageId and creates no passage item. Its Open it link targets the fixture detail route.
Notebook index Proof: seven cases distinguish a real row, an honest live empty state, mobile/standalone containment, anonymous gating, and service-worker document replay. Limit: an authenticated BFF refusal silently substitutes three review fixtures. The cards link to /nisaba/notebook?id=..., not the BFF-provided /workspace/notebook/:id launch path.
Durable member state Proof: production requires a snapshot sink, hydrates nisaba-study-workspaces before traffic, awaits each candidate snapshot before exposing the mutation, rolls back failed writes, restores notebook/annotation relationships, and returns 503 when required persistence is unavailable. Limit: it is one ordered snapshot for all subjects, not row-level notebook storage, and the named web API cases do not restart Postgres.
Annotation capture Proof: the live workspace submits selection offsets/excerpt, note, color, visibility, tags, notebook ids, and evidence ids. The BFF validates referenced ids, creates or updates the owner record, and automatically synchronizes its annotation item into every associated notebook before durable acknowledgment. Limit: named browser cases seed an annotation through HTTP and then update/archive it; none drives real text selection through browser creation and reads the resulting notebook item back.
Dedicated item API Proof: POST /v1/nisaba/notebooks/:id/items resolves passage, annotation, grounded-evidence-view, and compare refs; the passage case proves a launchable item, duplicate idempotency, and no mutation for an unknown ref. Limit: the current reading component never calls this route for passage, evidence, or compare capture.
Workspace study note Proof: the notes inspector captures context, title, body, and tags, keeps up to 24 notes under oshun.nisaba.study-notes, and has browser and analytics evidence. Limit: Save note writes only localStorage. The visible Saved to ... status and Durable notes stay attached ... copy do not represent a BFF notebook or annotation mutation.
Citation workspace Proof: the browser builds and can copy/download Citation, BibTeX, RIS, CSL-JSON, Markdown, and JSON for current artifacts; tests exercise live passage/source reads, format changes, copy status, links, and enabled download controls. Limit: output is synthesized from current title, meta, summary, route, selected passage, and access time. It has no canonical citation id, edition pin, DOI authority, immutable locator, source hash, or signed manifest.
Notebook detail and exports Proof: /nisaba/notebook renders a rich no-index specimen, and browser probes validate its fixture-derived Markdown, BibTeX, minimal PDF, and print actions. Limit: the page accepts no id, calls getNisabaNotebook() with no subject or notebook argument, and always returns the Renata K. fixture. Cite this and Resolve remain inert.
Data lifecycle Proof: customer export includes notebook and annotation records; account deletion erases the exact subject, preserves neighbors, persists a restart-safe fence, and rejects stale recreation with 409. Limit: browser-local study notes and fixture exports are outside that server lifecycle, and no joined named browser case requests export or erasure after capture.
Studio lifecycle Proof: source deletion runs a durable saga, removes media and derived export objects, tombstones study records, and opens review tasks for affected Nisaba notebooks instead of rewriting them. An owner may also hard-delete an archived project only after its source list is empty. Limit: project deletion tombstones the project without cascading source or Nisaba records. The Oshun account export/deletion registry covers legacy BFF notebooks/annotations, not nisaba_study.notebook or study_card; the adapter exposes no author-scoped list/delete contract, so Studio records have no demonstrated DSAR erasure path.
Named automation Proof: the nine legacy Playwright files contain 50 cases, while four Studio study browser files add nine real-stack cases. Six launch-surface component cases, 15 adapter cases, 11 publication cases, and at least 29 environment-gated walking-skeleton cases were present at this reconciliation. The service suite covers grant correction, renewal, revocation, quarantine review, allowed actions, layered resolution, non-mutating change simulation, and ordered rights-audit history through the generated client. Limit: its newest question/source-management cases are adjacent service evidence, and the browser still only creates the initial grant; the evidence spans two notebook stores, two clients, localStorage, fixtures, and generated metadata rather than one cross-client capture-to-canonical-citation run.

Evidence map#

The map reads from one selected client surface into two shipped durability lanes. Solid edges stay inside an authority. Dashed edges show where a client crosses into a different store or substitutes derived/specimen output; those boundaries are why the whole page is still partial.

flowchart TB S[Client surface] --> A[Legacy reading and annotation UI] S --> D[Studio study UI] A --> B[BFF owner record and synchronized item] B --> C[Awaited nisaba-study-workspaces snapshot] D --> E[Session proxy and study service] E --> F[Validated project anchor] F --> G[Nisaba adapter mints notebook and card refs] G --> H[Nisaba Postgres current revisions] H --> I[Rights-filtered study-trail export] C -. legacy links ignore stored id .-> J[Renata K. fixture and exports] C -. browser-only note .-> K[LocalStorage study note] C -. metadata-derived output .-> L[Six citation formats] H -. separate authority and no legacy hydration .-> C

Proven observations#

The historical pass proved route repair, not the named lifecycle#

  • The old walk correctly recorded that the notebooks index and new-notebook routes no longer returned 404, and that the create form could reach a real endpoint. Those were useful launch checks.
  • Its generic pass collapsed several different outcomes: a rendered list, an attempted write, a passage annotation, a captured notebook item, a citation, and a stored-notebook export. The preserved evidence reaches only the first two.
  • “0 persistent failures” described the walker's visible route session. It was not a BFF restart result, a snapshot check, a second-account isolation test, or an export verification.
  • The route now has far stronger repository evidence than the old result knew about, but that evidence also makes the missing browser joins more precise.

The Studio study route has become a second real capture authority#

  • /studio/study still leads with the manual-first capability inventory, but it now mounts StudyWorkspaceApp below it. Study projects/source ingest and playback/annotation link to that live section; Nisaba notebooks and Library remain real destinations. Ten craft lenses expose honest manual-annotation vocabularies without analyzers; only automated lens analysis is marked Not yet available without a control.
  • The client drives project creation, work registration, deny-before-rights ingest, playback, manual segments and anchors, observations, a Nisaba notebook, study cards, study-trail export, and source deletion. It holds only the HttpOnly Oshun session cookie.
  • /api/study/[...path] verifies that session through the BFF refresh exchange, mints a five-minute study token, and proxies GET/POST/DELETE to the configured service. Missing service URL/signing secret returns 503; missing or refused session returns 401 instead of a fixture success.
  • Four Studio Playwright suites contain nine cases over the real-stack harness: four accessibility and keyboard-driven journeys, one alignment-map journey, one epistemic-type journey, and three walking-skeleton cases including export, deletion, expiry, and accessibility. They are substantive product evidence, not the six launch-surface component cases.

Studio authors Nisaba-native records, with two important write boundaries#

  • The notebook form requires an existing anchor, but it always selects trail.anchors[0], appends [^1] to the narrative, and sends one ^1 citation. The browser offers no anchor picker, marker editor, multi-citation composer, publication control, or link into the resulting stored record.
  • The study route validates the project tenant and every cited anchor before it calls the adapter. Nisaba-owned code mints opaque nbk_ notebook and crd_ card refs; the nisaba_study schema stores every revision and enforces one current revision. Card append supersedes the notebook to list the card.
  • Publication widening is a separate, shipped service route. It verifies project tenant, notebook project and tenant, author-or-project-owner status, and collaboration/publication rights for every cited work; narrowing is allowed and both outcomes are audited. The current Studio UI does not expose that route.
  • Notebook creation writes the Nisaba database before adding the ref to the Yemaya project. Card append writes the card before superseding the notebook. The first sequence spans databases and the second spans tables; neither is wrapped in a transaction or compensating rollback, so a later write failure can leave an orphan notebook or card. A notebook supersession likewise marks the former revision before inserting the next one without a surrounding transaction.
  • More seriously, the card endpoint validates each supplied anchor against the request's projectId, but it does not verify that the target notebook belongs to that project, tenant, or actor. The adapter fetches by opaque ref and then supersedes that notebook. Knowledge of another ref is therefore enough to cross the intended authorization boundary; no named test exercises that case.
  • Production wires the adapter only when NISABA_DATABASE_URL is present; an absent adapter makes notebook routes return 503. A completed study export reads Nisaba notebooks into the rights-filtered document, records an export reference, stores the JSON in the object store, and returns a five-minute presigned URL. It is an authoritative study-service bundle, not a formatted scholarly citation.
  • Source deletion deliberately does not mutate a Nisaba notebook that cites the deleted work. The durable saga captures affected refs while anchors still exist, tombstones Yemaya records and removes object/export bytes, then opens affected-decision review tasks for the notebooks.
  • Account deletion is a different boundary. The BFF export/erasure registry includes its legacy notebook and annotation partitions, but no integration enumerates or deletes nisaba_study.notebook or study_card rows by author. The new Studio records therefore have no demonstrated customer export or account-erasure path.

Notebook creation and notebook opening use different meanings of “passage”#

  • /nisaba/notebook/new is a real client form. It requires a two-character title, offers a keyboard-operable private/unlisted/public radio group, attaches bearer and CSRF headers, and reports explicit HTTP or offline failure.
  • The optional field is labelled First passage, but buildNotebookSummary simply trims that text and sends it as summary. The payload contains title, summary, visibility, and empty tags. It does not contain linkedPassageId, selection offsets, a source id, or an item body.
  • The created response is real and the focused E2E reads title, summary, and visibility back through GET /v1/nisaba/notebooks. The success panel then offers /nisaba/notebook?id=<created id>.
  • The index repeats that destination for every live or fallback row. In contrast, the BFF serializes a notebook's launch target as /workspace/notebook/<id>, which the Nisaba domain workspace can use to select a notebook summary while keeping the reading frame mounted.
  • /nisaba/notebook receives neither searchParams nor an authenticated subject. It calls a zero-argument getNisabaNotebook(), and that function returns getNisabaNotebookFixture(). The query id is therefore decorative.
  • The index's real empty branch is honest, but its failure branch is not distinguishable in the rendered copy. When bffGet returns null, the page shows On the citadel, The night watch, and Quiet hour as three held notebooks with current-relative edit dates.

Legacy BFF notebook and annotation writes are ordered and durable#

  • NisabaConsumerStateStore retains member-authored notebooks, annotations, saved passage ids, and study reminders in one NisabaStudyWorkspaceSnapshot. Shared corpus passages, manuscripts, compare views, and grounded evidence are deliberately recomputed rather than copied into the member snapshot.
  • Production calls requireDurableNisabaStudyWorkspaces() before startup. When the admin snapshot database is configured, startup loads nisaba-study-workspaces and binds the save sink before accepting traffic.
  • Notebook create/update/item capture and annotation create/update clone the current record, apply a candidate mutation, await sink.save, and only then publish the candidate to the visible in-memory record. A failed snapshot becomes nisaba_study_workspace_persistence_unavailable, and the route sends 503 without exposing the candidate.
  • Mutations share a global ordered tail and a subject tail. Tests prove rollback after one failed snapshot, recovery on the next write, and deterministic create/delete race outcomes. They do not provide an HTTP revision precondition for two editing clients; the server serializes arrival order.
  • The restart test proves that annotation notes and generated notebook items survive snapshot restore. The real-Postgres test is environment-gated and exercises saved-passage/reminder partitions while retaining a notebook; it is not a deployed browser journey for notebook capture.

Annotation association is now a real notebook-item write#

  • The reading workspace captures a real DOM selection, supplies its excerpt and offsets, and defaults the annotation form to the selected notebook id. Create and update mutations go through the shared BFF hooks.
  • The route requires authentication plus domain:* or domain:nisaba, validates the passage, notebook ids, evidence-view ids, selection, note, color, and visibility, and binds the write to authContext.userId.
  • synchronizeAnnotationNotebookItems removes an older copy of that annotation item, rebuilds it from the current note and passage, inserts it for each notebook id still associated with the annotation, sorts the items, and bumps the notebook update time. The durable test reads that relationship after a simulated restart.
  • This corrects the earlier journey claim that notebookIds was merely a loose association. It is a materialized notebook item today.
  • Archive is a status update, not deletion. Because synchronization keys on notebookIds, not active status, archiving an annotation leaves its notebook item present unless the association is separately removed.
  • The four-case annotation API spec does not attach a notebook id. The broader browser specs seed associated annotations through HTTP and exercise live update/archive UI. No named test selects passage text, clicks the browser create control, observes Highlight saved, and then performs a notebook detail read-back for that same annotation item.

The dedicated item route is broader than the current browser capture UI#

  • POST /v1/nisaba/notebooks/:notebookId/items accepts exactly four kinds: passage, annotation, grounded-evidence-view, and compare. It resolves the ref against the caller's seeded/shared view of the Nisaba record and fails closed if the notebook or referenced resource is missing.
  • The passage API case proves a deterministic item id, nonempty title, source- derived summary, launch path, revision bump, and idempotent duplicate replay. The unknown-ref case proves revision and item count stay unchanged.
  • The new-notebook form never calls this route. Neither the selection handler nor citation/source controls call it for passage, evidence, or compare. Only annotation association reaches a notebook item automatically through the annotation mutation.
  • The index reports passageCount from items whose kind is exactly passage. An annotation captured into a notebook increments annotationCount, not the visible passage count on that index card.

The workspace note composer is local continuity with durable-sounding copy#

  • handleSaveNote builds a NisabaStudyNote with the selected notebook id and title, passage anchor, source label, context frame, body, tags, and timestamps. It prepends the record to localStorage and caps the array at 24.
  • The corresponding draft store, collections, study plans, and density mode are also browser-side continuity. The split-view test explicitly reads the oshun.nisaba.study-notes key after the save.
  • No note-save branch calls the notebook, item, or annotation endpoint. It does not update the BFF revision, materialize a notebook item, enter the customer export bundle, or cross devices through the account.
  • The interface nevertheless says Saved to and Durable notes stay attached to . “Attached” here means the local record carries the notebook id; “Durable” is not supported by the persistence authority.
  • Analytics evidence is useful but orthogonal: the event reports ids, counts, mode, and origin while omitting note text. It does not turn the local note into server state.

Citation output is functional browser serialization, not canonical scholarship#

  • buildNisabaCitationExportArtifacts collects current route artifacts and can append browser-local collection and study-plan artifacts. It de-duplicates by id and produces six formats per artifact.
  • The plain citation, BibTeX, RIS, and CSL-JSON all identify the author as Oshun Nisaba and use the browser's access date. Markdown and JSON retain title, metadata, summary, route, and selected passage context. Copy and Blob-download controls are real.
  • The citation-trail panel derives a primary source step, optional manuscript witness, and up to three contextual concept steps from the current passage and a BFF-provided source-lineage view. Its own source comment says the BFF does not ship canonical citation-trail data.
  • A “fully traced” panel state is computed from the grounded-view status; it is not a DOI resolution, edition lock, immutable locator, content digest, or signed provenance statement.
  • The named citation cases prove live passage hydration, four format transitions, JSON parsing, source-panel drill-down, copy status, link copy, and enabled download controls. They do not compare the output with a canonical citation service or reopen it after an edition change.

The rich notebook exporter operates entirely on authored specimen data#

  • The detail page always displays Renata K., On the ruling part, 14 entries, last edit, 11 min ago, a fixed word count, citation density, activity, a Lilith suggestion, and privacy copy. Most of those values are component literals; outline, pins, tags, recent activity, and retraction copy come from the fixture function.
  • Cite this and Resolve are LBtn controls without href or onClick. The retraction Keep with marker control is likewise presented as a pending write rather than a completed mutation.
  • The export block is real. It builds fixture-derived Markdown with footnotes, one BibTeX @misc per pin, a small single-page PDF string, and a print call. The six-case browser spec captures Blob filename, MIME type, and content for all three downloads and observes the print request.
  • robots: { index: false, follow: false } correctly emits noindex,nofollow. It does not authenticate the viewer, authorize the fixture as their notebook, or prevent a leaked URL from being requested.
  • The server's customer export is more authoritative than this page: its notebook partition includes the caller's real notebook and annotation records. The specimen exporter never reads that partition or the selected notebook id.

The named automation is deep but deliberately distributed#

  • The nine named Playwright files contain 50 cases: seven for the index, two for creation, four for annotation HTTP, five for notebook HTTP, 18 for the split workspace, five for reading/compare/annotation, six for capture/cite exports, one for analytics, and two for Nisaba-to-Metis study handoff.
  • Four Studio study Playwright files add nine cases: four accessibility and keyboard-driven journeys, one alignment-map journey, one epistemic-type journey, and three walking-skeleton cases. The walking skeleton authors a notebook and card, downloads a study-trail export containing the notebook, survives an app restart, deletes source derivatives, and checks rights expiry against real Postgres, MinIO, ffmpeg, and a separate Nisaba database when the harness is up.
  • The launch inventory adds six component cases. The adapter has nine conformance plus six focused cases, the publication gate has 11, and the service walking skeleton had at least 29 environment-gated cases at this reconciliation; those counts overlap capabilities rather than representing additional browser journeys.
  • Six of those service cases drive the generated client's rights lifecycle: correction/renewal/revocation, quarantined-grant approval, current allowed actions, an action-specific layered resolution with appeal context, a non-mutating revoke simulation, and chain-ordered rights-audit history. The Studio browser still calls only grantRights; it exposes no control for those subsequent review and decision operations.
  • The twenty-seventh service case drives an adjacent question-first lifecycle: ask, rescope, investigate, reject an evidence-free answer, abandon, list, and replay history. StudyWorkspaceApp calls none of those question methods, so that case is not notebook-capture coverage.
  • Two later cases read source detail/deletion impact and resolve source-identity candidates. They likewise deepen the shared service, not the notebook/citation browser path. The source gate therefore pins the relevant behaviors and only a lower bound for this actively growing global suite.
  • Many cases use the real BFF and unique authenticated subjects. The index also proves real service-worker document replay and phone containment; the create form proves CSRF and text-safe telemetry; the citation/export probe inspects generated bytes.
  • state-durability.test.ts adds 13 unit cases for write-before-ack snapshots, restart restoration, failure rollback, category erasure, fences, and races. nisaba-durability.test.ts adds two HTTP failure cases. The one Postgres case is skipped without a database URL.
  • No one case joins: legacy browser text selection → BFF annotation and awaited snapshot → synchronized item → Studio nbk_ record → stored-notebook UI → edition-pinned formatted citation → export → account erasure across both stores. The Studio journey is real, but it is a separate client and contract.

Boundaries and gaps#

  • A seed-passage label is not a captured passage item. The create form maps that text to notebook summary and sends no source reference.
  • A durable notebook is not the page opened by ?id=. The BFF record is real; /nisaba/notebook ignores the id and renders a fixture.
  • A Studio notebook is not the legacy BFF notebook. It has a Nisaba-native ref and durable nisaba_study revisions, but neither legacy notebook page hydrates it and the Studio client does not open a notebook detail view.
  • A service rights lifecycle is not a browser review console. The generated client and integration suite exercise correction, renewal, revocation, quarantine review, allowed actions, layered resolution, simulation, and audit history, but the current Studio client only creates the initial grant.
  • Ordered writes are not one transaction. Nisaba notebook persistence precedes the Yemaya project-ref write across databases; card insert precedes notebook supersession, and revision marking precedes revision insert, without a transaction or compensating rollback if the later statement refuses.
  • An opaque notebook ref is not authorization. The Studio card route checks the supplied anchor's project but not the target notebook's project, tenant, or author before it supersedes that notebook.
  • Legacy account erasure is not Studio notebook erasure. The BFF deletion fence covers its snapshot records, while the separate nisaba_study tables have no wired author-scoped export/delete contract.
  • A fixture fallback is not an honest live-data state. The index substitutes three authored notebooks without a degraded or review-data marker.
  • A browser-local note is not a durable notebook note. LocalStorage is the only note-write authority despite the UI's durable wording.
  • An automatic annotation item is not a browser-proven capture lifecycle. The store synchronizes it, but the named browser cases do not drive selection creation and item read-back as one path.
  • An archive is not removal from the notebook. Archived annotations retain their notebook item while notebookIds remains attached.
  • A serialized arrival order is not optimistic concurrency control. The API returns revisions but accepts no expected revision or If-Match condition.
  • A generated citation format is not a canonical edition pin. Browser metadata and access time do not establish immutable scholarly authority.
  • A derived source trail is not a signed provenance manifest. Grounding status selects presentation confidence without hashing the cited edition.
  • An exportable fixture is not an export of the selected stored notebook. Markdown, BibTeX, PDF, and print all serialize authored Renata K. data.
  • noindex,nofollow is not access control. It is crawler guidance only.
  • A service-worker replay is not a fresh server read. The offline index case deliberately replays the cached authenticated document.
  • Server erasure is not browser-note erasure. The deletion runner fences durable notebooks and annotations; the local note key is a separate client lifecycle.
  • Fifty-six web cases are not one joined capture-to-canonical-export journey. The set deeply proves two service authorities plus independent API, localStorage, fixture, and browser-serialization seams.

Re-run evidence#

The 2026-07-20 work reconciled source and Docs Center evidence after the Studio study stack landed upstream. It did not execute the 13 application Playwright files, the real-stack service suite, or the three legacy BFF durability suites. A fresh product run should retain durable artifacts rather than another ephemeral walker:

bash
pnpm --dir apps/oshun/web exec playwright test -c playwright.config.ts e2e/nisaba-notebooks-index.spec.ts e2e/nisaba-notebook-new.spec.ts e2e/nisaba-annotation-bff.spec.ts e2e/nisaba-notebook-bff.spec.ts e2e/nisaba-split-view.spec.ts e2e/nisaba-reading-compare-annotate.spec.ts e2e/nisaba-notebook-capture-cite.spec.ts e2e/nisaba-analytics.spec.ts e2e/nisaba-metis-study-prompts.spec.ts --project=chromium --workers=1
pnpm --dir apps/oshun/web exec playwright test -c playwright.config.ts e2e/studio-study-a11y.spec.ts e2e/studio-study-alignment-maps.spec.ts e2e/studio-study-epistemic-types.spec.ts e2e/studio-study-walking-skeleton.spec.ts --project=chromium --workers=1
pnpm --dir apps/oshun/web exec vitest run src/app/studio/study/__tests__/study-page.spec.tsx
pnpm --dir libs/nisaba/study-adapter exec vitest run src/adapter.spec.ts src/conformance.spec.ts
pnpm --dir libs/yemaya/study-workspace exec vitest run src/notebook-publication.spec.ts
STUDY_PG_REQUIRED=1 pnpm --dir apps/yemaya/svc-study-workspace exec vitest run src/__tests__/walking-skeleton.integration.spec.ts
pnpm --dir apps/oshun/bff exec vitest run src/nisaba/state-durability.test.ts src/routes/nisaba-durability.test.ts
OSHUN_ADMIN_DATABASE_URL=... pnpm --dir apps/oshun/bff exec vitest run src/nisaba/state-durability.integration.test.ts

Retain the commit and environment, authenticated subject and adjacent subject, create payload and response revision, snapshot store and commit result, selected passage offsets, annotation id, synchronized notebook item, restart read-back, index provenance state, exact page opened from the notebook link, citation format bytes, Studio project/anchor/nbk_/crd_ refs, both database commit results, study-pack object and signature status, exported notebook id and bytes, customer-export row, erasure receipt/fence, and the final state in both server and browser storage.

Source trail#

Cross-references#

Open questions#

  • Enforce project, tenant, and author/owner authorization on Studio study- card append before any lookup or mutation of the target notebook.
  • Make the Nisaba notebook/card write and the Yemaya project/notebook- revision write atomic, or add idempotent compensation and orphan repair.
  • Decide whether legacy BFF notebooks and Studio nbk_ notebooks converge behind one reader/detail route, or label them as deliberately separate record families in every client.
  • Let Studio authors choose cited anchors and markers, inspect the stored notebook/card, and invoke the shipped publication gate from the UI.
  • Add author-scoped Studio notebook/card partitions to customer export and account erasure, with restart-safe deletion fencing across the separate Nisaba database.
  • Route live index and create-success links to the real /workspace/notebook/:id surface, or make /nisaba/notebook?id= hydrate that exact stored record and its items.
  • Rename First passage to Summary or send a resolvable linkedPassageId/item capture instead of storing free text as summary.
  • Remove the silent notebook-index fixture fallback or label it explicitly as review data with a retryable degraded state.
  • Persist workspace study notes through a durable, exportable, erasable note contract; until then, replace Durable notes and Saved to copy with accurate browser-local language.
  • Add a real-browser selection → annotation create → synchronized notebook item → restart read-back case under one authenticated subject.
  • Define archive semantics for associated annotation items and expose an explicit detach or delete path.
  • Add expected-revision/If-Match conflict semantics and a reader-facing resolution path for concurrent notebook or annotation edits.
  • Define canonical citation ids, edition/version pins, stable locators, content hashes, manifests, and retirement/replacement behavior before calling client-generated output canonical.
  • Export the selected stored notebook rather than the authored fixture, and decide whether Chicago, APA, MLA, SBL, or CSL style rendering is in scope.
  • Replace or clearly label the Renata K. specimen's last-edit, entry count, word count, citation density, Lilith suggestion, privacy, and retraction controls.