# Compliance patterns

> **Mandatory.** These four patterns are not negotiable. They are the structural enforcement of ASK's brand promise. Any PR that touches them requires `@ask-security` review.

To maintain structural compliance and ensure user safety, the design system enforces **deterministic visual components that govern user behavior without manual intervention**. The user doesn't have to remember to be careful — the interface remembers for them.

---

## Pattern A — Verified Citation Block

### Why

To combat the *Oracle Illusion* and meet strict AI auditing criteria, **system outputs can never appear as a single block of unverified text**. Honesty is mandatory.

### UI requirement

Every factual assertion must contain an **inline, interactive citation tag**.

```
The Q4 manufacturing tolerance for the X-7 valve is 0.05 mm [1], with a
maximum sustained operating temperature of 140°C [2].

  [1] QMS_Manual_v3.pdf, Page 12
  [2] X-7_DataSheet_2025.pdf, Page 4
```

### Interaction

Clicking a citation tag must **instantly open a sidebar pane** that displays:

- The exact semantic text segment that grounded the assertion.
- The source file origin: filename, page (or section), retrieval timestamp.
- A link to open the source document in full.

### Microcopy

| Element | Copy |
|---|---|
| Citation chip | `[N]` — superscript-style, monospace, color `state.info` on hover. |
| Sidebar header | *Source for citation [N]* |
| Source label | *<filename>, Page <n> · Retrieved <relative time>* |
| Missing source | *Source document unavailable — output suppressed.* |

### Forbidden

- ❌ Citations as plain text "(see source 1)". Must be interactive.
- ❌ Citations that point to "the model's training data" — invalid source.
- ❌ Generated output that has no citations at all — must be suppressed entirely, not rendered.

### Figma component

`agentic/citation/chip` and `agentic/citation/source-pane`. See `03 — Patterns` file.

### Brand pillar served

**The RAG Engine — Contextual Truth.** Without Pattern A, the pillar is a slogan.

---

## Pattern B — Human-in-the-Loop (HITL) Validation

### Why

When an agentic workflow requests a write operation to an external system (Jira ticket, ERP update, contract signature, payment authorization), **accidental execution must be structurally impossible**. Single-click submit is a vulnerability.

### UI requirement

Standard single-click submit buttons are **forbidden** for external writes.

Use one of two explicit double-action patterns:

#### B.1 — Slide to Approve

A draggable handle that must traverse the full width of the action bar before the action fires. The handle:

- Resets if released before the threshold.
- Shows the precise payload above the slider.
- Uses `state.warning` for the track until the threshold, `state.success` after.

#### B.2 — Multi-checkbox Confirmation Panel

For payloads with multiple consequential fields, the user must explicitly tick a checkbox per field before the action button enables:

```
☐ I confirm the recipient: john.smith@acme.com
☐ I confirm the amount: € 12,400.00
☐ I confirm the target system: SAP S/4HANA · europe-west-1

  [ Confirm and Write to SAP ]   ← disabled until all three checked
```

### Required microcopy

Always present, immediately above the action:

> *Verify target details below. Confirming this action will write data permanently to [Target System].*

### Forbidden

- ❌ Single-click submit on any external write.
- ❌ Confirmation dialog as the *only* gate — the dialog can be muscle-memory'd through. The slider or per-field checkboxes force a deliberate motor action.
- ❌ Auto-progressing the slider for "convenience."
- ❌ "Don't show this again" toggles. Every external write is a fresh decision.

### Figma component

`compliance/hitl/slide-to-approve`, `compliance/hitl/multi-checkbox`. See `03 — Patterns`.

### Brand pillar served

**Policy as Code — Invisible Governance.** Compliance lives in the interaction, not the manual.

---

## Pattern C — Active Guardrail Interventions

### Why

When middleware filters intercept a request to scrub sensitive data (PII) or prevent out-of-bounds topics, **the system must remain operational while transparently alerting the user**. Silent guardrails erode trust; loud guardrails interrupt flow.

### UI requirement

Calm, non-disruptive **inline warning bars** or **toast notifications**. Never a modal.

Two tones:

#### C.1 — Active (informational)

The guardrail did its job; the operation proceeds. Use `state.info` palette.

> *[Guardrail Active]: PII Data detected. Automatically anonymizing names and IP addresses before processing.*

#### C.2 — Block (blocking)

The guardrail refused. Use `state.warning` palette (not `state.danger` — danger implies error; this is policy).

> *[Guardrail Block]: Out of scope. This App is restricted from processing data outside its functional domain.*

### Interaction

- Both tones are **dismissible** (Active) or **acknowledge-only** (Block).
- Both tones link to *Why?* — a tooltip or pane explaining which guardrail fired and which policy it implements.
- Block bars include a *Request review* link routing to the workspace administrator.

### Microcopy patterns

| Tone | Prefix | Pattern |
|---|---|---|
| Active | `[Guardrail Active]:` | What was detected → what was done. |
| Block | `[Guardrail Block]:` | What was attempted → why it stopped → how to proceed. |

### Forbidden

- ❌ Generic "Something went wrong" — guardrails are not errors.
- ❌ Red color tone for blocks — they're policy decisions, not failures.
- ❌ Hiding the *Why?* — opacity erodes trust.
- ❌ Modal dialogs that block the rest of the surface.

### Figma component

`compliance/guardrail/active`, `compliance/guardrail/block`. See `03 — Patterns`.

### Brand pillar served

**Walled Garden + Policy as Code.** The user sees the wall *and* understands its purpose.

---

## Pattern D — Implicit RBAC Filtering (Zero Trust UI)

### Why

Permissions in ASK are the strict intersection of:

- The **user's** corporate identity (Role-Based Access Control).
- The **app's** configuration manifesto.

Showing an unauthorized action — even as disabled — **reveals the access model to unprivileged users**, creating attack surface and UX friction.

### UI requirement

Users must **never see options they cannot execute**. Buttons, actions, menu items, input paths, or navigation entries that exceed either the user's RBAC scope or the app's limitations must be **entirely omitted** from the interface.

### Design rule

**Do not use "disabled" or "grayed-out" states for unauthorized actions.**

| Do | Don't |
|---|---|
| ![omit](https://img.shields.io/badge/-Omit_the_item-1F8A5B) | ![disable](https://img.shields.io/badge/-Disable_the_item-C81B2E) |
| Filter the array of menu items at the source so only authorized actions render. | Render every action and toggle `disabled` based on permissions. |

### Why "disabled" is forbidden

1. **Information leakage.** A disabled "Delete tenant" button tells an attacker that the action exists.
2. **UX friction.** Disabled items pollute menus; users hunt for active ones.
3. **Audit confusion.** "I clicked it but nothing happened" generates support tickets.

### Implementation contract

Code-side: actions are derived from a permission-filtered selector. There is no `disabled` prop on action-menu items.

```ts
// ✅ Right
const actions = useAuthorizedActions(currentUser, currentApp);
return actions.map(a => <MenuItem key={a.id} {...a} />);

// ❌ Wrong
return ALL_ACTIONS.map(a =>
  <MenuItem key={a.id} {...a} disabled={!canPerform(a, currentUser)} />
);
```

A product-repo lint rule forbids `disabled` on action-menu items wired to RBAC selectors.

### Edge case — global navigation

Top-level navigation entries (sidebar items) follow the same rule: filter, don't disable. The only acceptable exception is *upgrade*-gated features in marketing screens, which are explicitly *not* RBAC and clearly labeled.

### Figma component

`compliance/rbac/menu-filtered` (do) and `compliance/rbac/menu-disabled` (don't, included as a counterexample with a red strike).

### Brand pillar served

**Walled Garden — Trust & Sovereignty.** Zero trust extends to the UI itself.

---

## Compliance pattern matrix

For surface authors, here's the quick decision table:

| Surface displays… | Required pattern(s) |
|---|---|
| Agent-generated text | A (citation) |
| External write button | B (HITL) |
| PII-bearing input | C (guardrail active, before processing) |
| Out-of-scope query | C (guardrail block) |
| Any action menu | D (RBAC filtering) |
| RAG-grounded answer | A + C if PII present |
| Vertical App "Submit" | B + D (and A for any displayed reasoning) |

---

## Auditing your surface

Before opening a PR that introduces a new product surface:

- [ ] Every model output has a citation slot wired up (Pattern A).
- [ ] Every external write goes through `<SlideToApprove />` or a multi-checkbox confirm panel (Pattern B).
- [ ] PII-handling steps surface an inline `[Guardrail Active]` bar (Pattern C).
- [ ] Action menus pull from a permission-filtered selector — no `disabled` items (Pattern D).
- [ ] `@ask-security` is added as a reviewer.

If you can't tick all five, the PR isn't ready.
