---
path: /studio/isis/retention-policies
surface: studio
domain: isis
auth: signed-in + studio entitlement (NOT AAA-gated)
source: apps/oshun/web/src/app/studio/isis/retention-policies/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);
  2026-06-30 addendum: `studio-isis-retention-policies.spec.ts` proved the
  direct route remains hard-blocked by the Studio Isis boundary, then drove the
  localhost-only lane-bypass route against the real local BFF, including policy
  catalog, seeded records, exported-customer and legal-hold evaluations, scan
  endpoint, duplicate/pending/loading/empty/error/unauthorized/anonymous states,
  route-map articles, and sibling quick-actions.'
---

# Studio · Isis · Retention Policies

## Purpose

Admin lane console for the artifact retention/deletion policy. The operator
evaluates a 3D model artifact (kind, created date, export and legal-hold flags)
against the retention policy; the engine returns the keep/delete decision and
the governing rule. Reads the policy and evaluates via
`/v1/admin/isis/retention-policies`; admin-scoped and fail-closed.

## Entry points

- Embedded as the "Retention Policies Lane" inside `/studio/isis/outputs`
- Sibling quick-action from `/studio/isis/lineage-graph`
- Studio index (`/studio`)
- Direct URL / bookmark

## Layout regions

`page.tsx` mounts `<ShellLayout active="studio">` (no breadcrumb panel) and
three panels: the workspace, the Route Map, and sibling quick-actions.

- **Header**: shell header
- **Workspace panel** (`data-isis-retention-policies-workspace`):
  - `<h1>` (`WorkspaceHeading`) "Isis Retention Policies Workspace"
  - Summary paragraph (`data-retention-summary`)
  - Policy (`data-retention-policy`, `data-retention-rule`)
  - Evaluate form (`data-retention-form`)
  - Evaluated records (`data-retention-records`, `data-retention-record=<id>`
    with `data-retention-decision` / `data-retention-verdict`); empty state
    `data-retention-records-empty`
- **Route Map panel** (`data-isis-retention-policies-route-map`):
  `<h2>Route Map</h2>` over the route map (5 entries)
- **Sibling quick-actions panel**: `/studio/isis/lineage-graph`, `/studio`

## States

- [x] **Loading** — `data-retention-loading`
- [x] **Unauthorized** — 401/403 admin-scope fail-closed;
      `data-retention-unauthorized`
- [x] **Error** — non-OK / malformed; `data-retention-error`
- [x] **Ready (form)** — policy + evaluate form render
- [x] **Empty** — no artifacts evaluated yet; `data-retention-records-empty`
- [x] **Result** — `data-retention-result` (`data-retention-status`) after
      evaluating

## Interactions

### Evaluate form (`data-retention-form`)

- [x] **Artifact id** (`data-retention-artifactid`, input)
- [x] **Label** (`data-retention-label`, input)
- [x] **Kind** (`data-retention-kind`, `<select>`)
- [x] **Created (date)** (`data-retention-created`, input)
- [x] **Exported to customer** (`data-retention-exported`, checkbox)
- [x] **Legal hold** (`data-retention-legalhold`, checkbox)
- [x] **Evaluate** (`data-retention-evaluate`, `type="button"`) —
      `POST /v1/admin/isis/retention-policies`

### Route Map

- [x] **Route-map articles** ×5

### Sibling quick-actions

- [x] **Open Isis Lineage Graph workspace** → `/studio/isis/lineage-graph`
- [x] **Back to Studio workspace index** → `/studio`

## Data & contracts

- **Reads**: `GET /v1/admin/isis/retention-policies` (policy + rules + evaluated
  records)
- **Writes**: `POST /v1/admin/isis/retention-policies` (evaluate an artifact)
- **Maintenance scan**: `POST /v1/admin/isis/retention-policies/scan`
  (continuous deletion-sweep over stored artifacts)
- **Realtime**: none
- **Caching**: client fetch on mount, `cache: 'no-store'`,
  `buildBffAuthHeaders()`
- **Auth/role check**: admin-scoped, fail-closed (401/403); route signed-in +
  studio entitlement (not AAA-gated)
- **Component sources**:
  - `apps/oshun/web/src/components/studio/StudioIsisRetentionPoliciesWorkspace.tsx`
  - `apps/oshun/web/src/components/studio/StudioIsisRetentionPoliciesRouteMap.ts`

## E2E coverage

- [`apps/oshun/web/e2e/studio-isis-retention-policies.spec.ts`](../../../../apps/oshun/web/e2e/studio-isis-retention-policies.spec.ts)
  — proves direct `/studio/isis/retention-policies` is still hard-blocked by the
  Studio Isis boundary, then drives the localhost-only
  `?__oshunStudioIsisLaneE2E=1` lane bypass in the real Next shell with browser
  requests forwarded to the real local BFF. Covered paths:
  - Admin direct navigation loads the active policy windows, seeded records
    (`art-recent-render`, `art-stale-upload`, `art-legal-hold`), form defaults,
    route-map articles, and sibling quick-actions.
  - The real BFF scan endpoint returns the deletion-due stale upload and
    blocking legal hold while excluding the in-window recent render at the seed
    clock.
  - Exported-customer evaluation persists an `ALLOW` record with the
    customer-export retention window (`retain until 2027-01-01`); legal-hold
    evaluation persists a `DENY` record with no delete date and legal-hold
    reason.
  - Required-field disabled state, pending `"Evaluating..."` label/lockout,
    duplicate seeded id rejection, loading, empty, 503 error, malformed catalog,
    non-admin unauthorized, and anonymous redirect-before-render are asserted.

## Cross-references

- Studio overview: [`../../studio-overview.md`](../../studio-overview.md)
- Also embedded in: [`studio-isis-outputs.md`](./studio-isis-outputs.md)
- Sibling routes:
  - [`studio-isis-lineage-graph.md`](./studio-isis-lineage-graph.md)

## Open questions / known gaps

- [ ] No breadcrumb on this route — navigation via sibling quick-actions
- [ ] Also embedded as a lane inside the Outputs aggregator
- [ ] Route-map sub-paths are declared but not yet implemented as separate pages
- [ ] Live screen-reader, touch-device, offline/PWA-cache, and
      telemetry-delivery passes still need a manual or dedicated-device run;
      automated coverage includes Playwright role/locator checks and the
      suite-wide axe pass.
