Skip to Content
EngineeringDecisions (ADRs)ADR 0027 Workbench roles: a UX and harness layer over the personas, never a permission

ADR 0027: Workbench roles: a UX and harness layer over the personas, never a permission

Status
Accepted
Date
Deciders
Founder

Context

Real people do not think from discovery to manufacturing at once: a medicinal chemist, a toxicologist, a CMC scientist and a regulatory writer each need their own first screen, their own tools and an agent that behaves in their vocabulary. The platform has ten RBAC personas whose bundles are the authorisation model; “role” already means an RBAC role in code (roles, role_assignments, org.roles.*, program.roles.*). The founder confirmed eight first-release roles and asked the design to justify more.

Decision

  • The new layer is a workbench role, written in full everywhere and never shortened to “role”. Fifteen keys (PRODUCT-CONTRACT.md 12.2): the founder’s eight with the regulatory role split into regulatory_strategist and medical_writer, plus analytical_qc_scientist, formulation_scientist, computational_biologist, biostatistician, ip_analyst, portfolio_head; bioanalytical, safety pharmacology and pharmacometrics are folded into existing roles with named skills.
  • A workbench role selects a home screen, a rail, a toolset, skills, a prompt, a rubric and memory lenses. It never grants a permission: the effective toolset is the harness toolset intersected with the run role’s tools and the allow-list computed from live permissions; record types are permission resources whose .manage key is held by a mapped persona. Fixed sentence: “Workbench roles change what you see first, never what you may do.”
  • Stored per person and program in users.settings.workbench_role[program_id] (USER_SETTING_WORKBENCH_ROLE, the eighth constant); set by the person through PATCH /me/settings or by a lead through PUT P/workbench-roles/{user_id} with a reason, both audited; cleared by the person with {workbench_role: {<program_id>: null}}, after which the role home returns to the persona home (contract 12.3, recorded 2026-09-16). GET /me carries user.settings, so the web reads the workbench role from the identity call (12.8). Fallbacks and delegation semantics are fixed in 12.2.
  • Catalogue in api/app/auth/workbench_roles.py with a JSON export mirrored by web/lib/workbench-roles.ts; coverage tests in make check (test_workbench_roles_cover_personas, test_workbench_roles_never_in_permissions, test_record_types_are_permission_resources, test_harness_toolset_subset, test_workbench_role_labels).

Consequences

  • No new persona, no new permission key, PERSONA_VERSION stays 3 in R4; EXPECTED_WORKBENCH_ROLE_COUNT = 15, WORKBENCH_ROLE_VERSION = 1.
  • R4 ships two harness prompts (medicinal_chemist, dmpk_tox_scientist); the other keys are selectable with the neutral persona harness.
  • Products stay the record of truth; the role home folds them under “All records” with labels from words.workbenchRoleLabels while the H1 keeps the contract name.

Alternatives considered

  • New RBAC personas per role: fifteen more bundles to keep in sync with the approval matrix, and a role would become a permission; rejected.
  • Hiding records a role does not own: folding, never removal, keeps the program legible to every member; rejected.
  • Fifteen harness prompts in R4: scope creep; two prompts plus the neutral harnesses ship first.

Follow-ups

  • Harness prompts for the remaining roles (R5; ip_analyst R6).
  • Roadmap roles: clinical operations lead, pharmacovigilance physician, data manager, alliance / BD.