feat: Worker portal Stage 6 — Studio live-mode composer

Description

Land the Studio live-mode composer. Jurisdiction admins edit composition surfaces (worker / supervisor / analyst dashboards, case-detail) in a real-time editor; changes write to the live-override layer via Stage-3 live override APIs (#491 (closed)). The composition loader picks up edits on next jurisdiction-wide render thanks to ADR-021's invalidate-on-write cache.

v1 scope note: the promote modal (originally part of this issue's scope) was descoped when ADR-023 was reframed and deferred to #507 (unified canopy config backend). In v1, admins promote live overrides to baseline via their jurisdiction's existing baseline-edit workflow (PR / Salt / manual edit) external to canopy — no POST /v1/composition/{surface}/promote endpoint in v1, no Studio-driven PR generation. When #507 ratifies a write-capable backend, the promote modal returns as a follow-up MR. Issue weight reduced 5 → 3 to reflect this scope cut.

Acceptance Criteria

  • Template at services/canopy-web/templates/studio/live_mode.html
  • Live composer:
    • Picker for surface (worker-dashboard / supervisor-dashboard / analyst-dashboard / case-detail)
    • Visual editor that mirrors the live surface (drag to reorder; hide/show; resize span within allowed_spans; change shell strategy per role for case-detail per ADR-021)
    • Save persists via Stage-3 PUT /v1/composition/{surface}/live (full patch-op list replace) or PATCH (append ops)
    • Composition loader picks up edits on next render via ADR-021's invalidate-on-write cache
  • "Live override matches baseline" hint per ADR-022 lifecycle: when a baseline refresh detects the patched composition equals the post-refresh baseline, Studio prompts "Archive this live override?" with explicit "Archive" / "Keep" buttons. Archive calls POST /v1/composition/{surface}/live/archive (#491 (closed)).
  • Gated to studio_admin role
  • Audit emitted on every live edit + archive per ADR-014
  • Playwright E2E: edit → save → live render reflects; archive prompt fires when live matches baseline; Archive button moves row to composition_documents_archive
  • axe-core WCAG 2.1 AA clean
  • CHANGELOG entry under === Added

Out of v1 (deferred to #507)

  • Promote modal (Studio-driven PR generation against jurisdiction baseline)
  • POST /v1/composition/{surface}/promote endpoint
  • Diff view of live overrides vs current baseline (TOML or JSON-merge-patch) — currently only exists implicitly via the "live matches baseline" hint; an explicit diff view returns with the promote modal when #507 lands

Blocked by

Context & References

  • Tracking issue: #460
  • Epic: &51
  • Plan: worker-portal-redesign.adoc, Stage 6
  • ADR-021: composability runtime + plugin model (cache invalidation contract)
  • ADR-022: composition override storage layering (Archive lifecycle, RFC 6902 patch ops)
  • #507: deferred promote modal pending unified config backend

Labels

type::feature, priority::medium, program::infrastructure, service::web, workflow::needs-spec, compliance::wcag-21-aa

Edited by Ghost User