---
path: /studio/authoring
surface: studio
domain: authoring
auth: signed-in + studio entitlement
source: apps/oshun/web/src/app/studio/authoring/page.tsx
status: walked
last_walked:
  '2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data
  (2xx), console/page-errors, expected content, screenshot verified; live
  screen-reader, touch, offline, and telemetry-delivery checks pending a manual
  AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md; body
  re-derived 2026-06-03 from current source (lane-console architecture)'
---

# Studio · Authoring

## Purpose

Compose Oshun Studio artifacts with the structured-block editor, live source
panel, preview-as-customer, evaluation harness, and AI-assist guardrails
(§16.2). `StudioAuthoringWorkspace` is seeded — it loads a `SEED_DOCUMENT` (a
"Morning Tara Practice" demo) and runs every client-side evaluator from
`@oshun/studio-authoring` against it — and additionally embeds one live,
real-backed `AuthoringReadabilityLane` wired to the Flesch readability scorer at
`/v1/admin/studio/readability`. (This is the seeded exception to the studio lane
pattern: there is no catalog fetch for the editor itself; only the readability
lane talks to the BFF.)

## Entry points

- **Studio root** (`/studio`) — discoverable as an authoring workspace
- **Review-approval-workflows, commenting-annotation-system,
  real-time-collaboration-substrate, asset-preview-pipeline,
  internationalization-localization** — link here via quick actions
- **Direct URL / bookmark** — yes

## Layout regions

`page.tsx` mounts `<ShellLayout active="studio">`, renders
`StudioAuthoringWorkspace`, then a `panel` of 5 `quickAction` links. There is no
Route Map panel on this route.

- **Header**: document title `<h1>` (`WorkspaceHeading`, shows `document.title`)
  + a metadata line (`templateId`, `locale`) and an autosave/lamport strip
- **Readability Scoring lane** (`<section data-rd-lane>`, `<h2 data-rd-heading>`):
  the only server-backed region — loads readability bands from
  `/v1/admin/studio/readability`, scores a pasted samples payload via `/score`
- **Two-column body** (`2fr 1fr`):
  - **Document blocks** (`data-studio-authoring-document-blocks`): each block in
    `document.blocks` as an editable card, marked
    `data-studio-authoring-block="<blockId>"` +
    `data-studio-authoring-block-kind="<kind>"` (heading / paragraph / image /
    citation); paragraph/heading blocks are editable textareas
  - **Right rail** (aside): Sources (`DEMO_SOURCE_SNIPPETS` with per-snippet
    "Cite on para-2" buttons, `data-studio-authoring-cite-snippet=<snippetId>`),
    Preview parity (`data-studio-authoring-preview-surface=<surface>` chiplets +
    `data-studio-authoring-preview-verdict`), Evaluation harness
    (`data-studio-authoring-evaluation-findings`), Publish readiness
    (`data-studio-authoring-publish-readiness`), AI assist
    (`data-studio-authoring-ai-instruction` + `data-studio-authoring-ai-verdict`)

## States

- [ ] **Loading** — server-rendered + client hydration
- [ ] **Readability lane loading / unauthorized / error / ready** —
      `data-rd-loading`, `data-rd-unauthorized` (admin scope 401/403),
      `data-rd-error`, then `data-rd-bands` + the score form
- [ ] **Initial seeded document** — heading + 2 paragraphs + image; image has
      alt text; the second paragraph trips the cautionary "always" phrase
- [ ] **Findings populated** — the second paragraph surfaces a tone-policy
      finding for "always"
- [ ] **Preview parity** — at least one preview surface flags a missing caption
      track on the image block
- [ ] **Publish blocked** — `readiness.ok === false`; missing list / unmet Isis
      gate ids (e.g. accessibility unmet when caption track is missing)
- [ ] **AI assist verdict** — default instruction passes; adding banned phrases
      ("cure" / "eliminates anxiety") flips the verdict to blocked with a reason
- [ ] **Drag-to-cite** — clicking "Cite on para-2" mutates `document.blocks`
      to add a citation block (via `applyDragToCite`)
- [ ] **Offline** — editor is fully client-side; only the readability lane needs
      the network

## Interactions

### Readability Scoring lane (live)

- [ ] **Samples (JSON)** — `textarea[data-rd-payload]`,
      `aria-label="readability samples json"` (e.g.
      `{ targetGrade, samples[{ sampleId, sentences, words, syllables }] }`)
- [ ] **Score readability** — `button[data-rd-submit]` (form `data-rd-form`
      submit) → `POST /v1/admin/studio/readability/score`; renders
      `data-rd-result` with `data-rd-avg-ease` / `data-rd-avg-grade` headline and
      `data-rd-sample-row` rows (`data-rd-ease` / `data-rd-grade` / `data-rd-band`)

### Editor blocks (per block)

- [ ] **Block card** (`data-studio-authoring-block="<blockId>"`,
      `data-studio-authoring-block-kind="<kind>"`) — heading/paragraph render an
      editable textarea (`onBlur` → `handleEdit`); image shows URL + alt;
      citation shows source id + locator
- [ ] **Autosave** — each edit runs `acceptAutosave` against in-page state and
      updates the lamport clock / autosave status string

### Sources panel

- [ ] **"Cite on para-2"** (`button[data-studio-authoring-cite-snippet=<id>]`)
      — calls `applyDragToCite('para-2', snippet)`; appends a citation block or
      reports "citation already present"

### Preview parity / Evaluation / Publish readiness / AI assist

- [ ] **Per-surface chiplet** (`data-studio-authoring-preview-surface`) — selects
      the active surface; verdict shows ✓ ready or N parity issue(s)
- [ ] **Findings list** (`data-studio-authoring-evaluation-findings`) — severity,
      kind, blockId, message
- [ ] **Publish readiness** (`data-studio-authoring-publish-readiness`) — ✓
      satisfied or "Blocked — missing: …" + unmet Isis gates
- [ ] **AI instruction textarea + verdict** — `evaluateAiAssistGuardrails` pass /
      blocked with reason + detail

### Footer quick actions

- [ ] 5 sibling links: Review and Approval Workflows, Commenting and Annotation
      System, Real-Time Collaboration Substrate, Asset Preview Pipeline,
      Internationalization & Localization

## Data & contracts

- **Reads (editor)**: in-page seeded `SEED_DOCUMENT`, `DEMO_TONE_POLICY`,
  `DEMO_SOURCE_SNIPPETS`, `DEMO_BINDINGS`
- **Reads (lane)**: `GET /v1/admin/studio/readability` (catalog: `bands[]`)
- **Writes (lane)**: `POST /v1/admin/studio/readability/score` (returns
  `{ result: { samples[], summary } }`)
- **Writes (editor)**: none — `acceptAutosave` / `applyDragToCite` run against
  in-page state only
- **Realtime**: none
- **Caching**: readability lane uses client `fetch` on mount, `cache: 'no-store'`
- **Auth/role check**: the readability lane is admin-scoped fail-closed
  (`admin:*` | `admin:studio`, 401/403) at the BFF; proxy `studio` gate on the
  route (signed-in + studio entitlement). Headers via `buildBffAuthHeaders()`.
- **Library**: `@oshun/studio-authoring` — `evaluateAuthoringWithPolicy`,
  `evaluateAllPreviewSurfaces`, `evaluatePublishReadiness`,
  `evaluateAiAssistGuardrails`, `acceptAutosave`, `applyDragToCite`,
  `citationDensityByBlock`

## Cross-references

- Parent: [`../studio-overview.md`](../studio-overview.md)
- Sibling: [`studio-compose.md`](./studio-compose.md),
  [`../collaboration/studio-review-approval-workflows.md`](../collaboration/studio-review-approval-workflows.md),
  [`../collaboration/studio-commenting-annotation-system.md`](../collaboration/studio-commenting-annotation-system.md)
- Source: `apps/oshun/web/src/components/studio/StudioAuthoringWorkspace.tsx`

## Open questions / known gaps

- [ ] The editor is seeded; only the readability lane is server-backed. Confirm
      the authoring-document persistence path once the workspace moves off
      `SEED_DOCUMENT`.
- [ ] Document the autosave latency budget — `acceptAutosave` currently runs
      synchronously against in-page state.
