feat: Worker portal Stage 3 — live override APIs (read/write/archive endpoints)

Description

Land the live override APIs that Studio (Stage 6) will call to read, write, and archive jurisdiction live overrides without touching git. These are the HTTP endpoints that mutate the DB-backed override tables; the composition loader reads them on subsequent requests.

v1 scope note: the original "promote" endpoint (POST /v1/composition/{surface}/promote producing a git PR) 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. This issue ships read + write + explicit Archive only.

Acceptance Criteria

  • HTTP endpoints on canopy-web per ADR-022's write API contract:
    • GET /v1/composition/{surface}/live — current live override doc for the authenticated user's jurisdiction
    • PUT /v1/composition/{surface}/live — write/replace live override patch-op list (full replace; If-Match ETag for optimistic concurrency)
    • PATCH /v1/composition/{surface}/live — append patch ops (Content-Type: application/json-patch+json)
    • DELETE /v1/composition/{surface}/live — revert live override (composition falls back to baseline)
    • POST /v1/composition/{surface}/live/archive — explicit Studio Archive per ADR-022 lifecycle (moves row to composition_documents_archive)
    • GET /v1/composition/{surface}/role/{role} — current role override (jurisdiction admin only)
    • PUT /v1/composition/{surface}/role/{role} — write role override
    • PATCH /v1/composition/{surface}/role/{role} — append patch ops
    • GET /v1/composition/{surface}/user/me — current user delta
    • PUT /v1/composition/{surface}/user/me — write user delta
    • PATCH /v1/composition/{surface}/user/me — append patch ops
  • Authorization: jurisdiction admin role can mutate live + role; users can mutate only their own delta
  • Every mutation emits a JWS-signed AuditEvent per ADR-014 (chain integrity extends across composition mutations)
  • Validation: every PUT/PATCH validates patch ops against ADR-021's Plugin.toml constraints (allowed_spans subset, known programs, known roles); test ops support optimistic concurrency per ADR-022 Decision 2
  • Cache invalidation: every successful write invalidates the CompositionKey in canopy-web's in-process composition cache per ADR-021's Option C.i decision (single-replica v1)
  • OpenAPI definitions via utoipa::path decorators
  • Unit + integration tests for each endpoint (auth, validation, audit emission, override readback, cache invalidation)
  • CHANGELOG entry under === Added

Out of v1 (deferred to #507)

  • POST /v1/composition/{surface}/promote — git-PR-generating endpoint. Until #507 ratifies the unified config backend + adds a write-capable backend impl, admins promote via their jurisdiction's existing baseline-edit workflow external to canopy.

Blocked by

  • Stage 3 composition loader issue merged (#490 (closed))
  • Stage 3 DB migrations issue merged (#489 (closed))
  • ADR-021 ratified (2026-05-20)
  • ADR-022 ratified (2026-05-20)

Context & References

  • Tracking issue: #460
  • Epic: &51
  • Plan: worker-portal-redesign.adoc, Stage 3
  • ADR-021: composability runtime + plugin model (canonical for cache invalidation + role filter semantics)
  • ADR-022: composition override storage layering (canonical for table schema + RFC 6902 patch ops + Studio Archive lifecycle)
  • ADR-014: JWS audit hash-chain (audit emission contract)
  • #507: deferred promote endpoint pending unified config backend

Labels

type::feature, priority::medium, program::infrastructure, service::web, workflow::needs-spec

Edited by Ghost User