# Subspace CMS — Ownership, Identity & Audit Policy

Ruling by Ray (Raydog), 2026-10-18, Inkwell. Pinned by Zora. This documents DELIBERATE policy
that matches current behavior (verified live 2026-10-18); a deviation is a DEFECT, not a mode.

## 1. No anonymous CMS path
Every Subspace CMS surface requires a Citadel login (Bearer JWT). Anonymous access exists ONLY on
the public-site render key (user 8888, api-sites.php, read-only). Any CMS endpoint that falls through
to anonymous is a defect.
- Enforced: every route in api-content.php calls requireAuth() as its first statement (401 otherwise);
  the only unauthenticated fallthrough is HTTP 404. The api.php records path requires an X-API-Key
  (apiKeyDbAuth); the 8888 public key is read-only via authorization.tableHandler.

## 2. Desk identity is never anonymized
Desk-tier users FUNCTION as Art Desk on the OWNERSHIP axis only (artist_id = 99). Their individual
Citadel id is tracked, displayed and logged everywhere else — never anonymized, never collapsed to 99
outside ownership.
- Proof standard: audit_log row uid=48 (Panda, desk) is recorded as user_id 48 on whoami and reassign,
  not 99. whoami returns the real user_id; uploaded_by stamps the real uploader on create.

## Ownership model (how the above is implemented)
- OWNER axis = media/gallery_items/... `artist_id` (reassignable). 99 = Art Desk.
- `uploaded_by` = actual Citadel uploader, server-stamped on create, IMMUTABLE (stripped on every update
  on both the JWT and X-API-Key paths).
- Role/attribution resolved from `site_members` (super_admin|admin|artist|desk + artist_id); non-members
  resolve to desk / Art Desk 99.

## Visibility (list reads, server-enforced, client cannot widen)
- admin/super_admin: all rows. artist: own artist_id + 99. desk/anon-as-Art-Desk: 99 only.

## Reassign valve (ownership transfer) — api-content.php ?action=reassign ONLY
- artist: may reassign a row ONLY if its current artist_id is in {own, 99}; target must be in the
  OWNER set. admin/super_admin: any row, owner-set target.
  ⭐ ADMIN LATITUDE (Ray 2026-10-19, Inkwell: "As admin I need that latitude"): admin and super_admin
  BYPASS the give-valve direction rules entirely — any row, any direction (e.g. Nikki -> anyone), target
  still in the owner set (422 otherwise), every admin reassign still audit-logged. Already the server's
  behaviour (`if (!$admin)` guards the direction block; proven live 2026-10-18 18:43 user 1 moved
  gallery_items 42 from 27 to 13). The one-way valve stays exactly as written for artists and desk. desk: NO (Ray 2026-10-18:
  "...not being allowed to force an image into an artists personal domain").
- Owner-set target = distinct site_members.artist_id for artist/admin/super_admin roles, plus 99
  (?action=owners returns it; the valve enforces it). A target outside it = 422.
- Ownership moves through NO other path: the X-API-Key records UPDATE strips artist_id.

## Carve-out (Ray's condition)
- Assigning an image to a component (instance_content, ?action=assign / ?action=unassign, e.g. the
  Fresh Ink component) is NOT an ownership transfer and is NOT gated by the valve. Art Desk retains it.

## Audit
- All verbs (reads and writes) log to audit_log via the shared pipeline, stamped with the actor's
  Citadel id. Reassign logs every outcome (200 from->to, 403 not_owner/role, 422 target_not_owner).
