# Layer 2 — Surface & Pattern files

## What this layer is

The surface and pattern layer sits between the root and individual component
rules. It has two responsibilities:

1. **Surface classifier** — determines _which product_ is being built before any
   component is touched.
2. **Surface rules** — defines interaction behaviour that applies globally
   across all components on that surface.

Together they answer: _"For this surface, what are the rules that override
component defaults?"_

---

## Where these files live

```
docs/patterns/
  CLAUDE.md                        ← surface classifier (always read first)
  internal-admin/
    CLAUDE.md                      ← surface rules for internal admin
    list-page.md                   ← feature pattern: list of records
    form-page.md                   ← feature pattern: create / edit (coming soon)
    detail-page.md                 ← feature pattern: record detail (coming soon)
  customer-portal/                 ← not yet defined
  website/                         ← not yet defined
```

---

## File 1 — The surface classifier (`docs/patterns/CLAUDE.md`)

### What it does

This is the agent's second read (after the root). Its only job is to map signals
from a PRD or feature brief to a named surface, then point the agent at the
correct surface rules file.

### What it must contain

**A signal-to-surface lookup table.** Words or phrases that appear in a PRD,
mapped to the surface they indicate:

| Signal in PRD                                                    | Surface         |
| ---------------------------------------------------------------- | --------------- |
| "admin", "internal", "back office", "ops", "manage", "dashboard" | Internal admin  |
| "customer", "portal", "my account", "self-service"               | Customer portal |
| "website", "marketing", "landing page", "public"                 | Website         |
| "mobile", "app", "iOS", "Android"                                | Mobile app      |

**A pointer to the surface rules file for each defined surface.** Undefined
surfaces should be flagged explicitly so the agent stops and asks rather than
guessing:

```markdown
| Surface         | Rules location                         |
| --------------- | -------------------------------------- |
| Internal admin  | docs/patterns/internal-admin/CLAUDE.md |
| Customer portal | Not yet defined — flag to the team     |
```

**A pointer to feature pattern files** for each surface:

```markdown
| Feature type                 | Pattern file                              |
| ---------------------------- | ----------------------------------------- |
| List of records with actions | docs/patterns/internal-admin/list-page.md |
| Create or edit a record      | docs/patterns/internal-admin/form-page.md |
```

**The canonical reading order** — a numbered list reinforcing the full sequence
from root to component. This is intentional redundancy: the more times the agent
sees the reading order, the less likely it is to skip steps.

```markdown
1. docs/patterns/CLAUDE.md ← surface classifier (this file)
2. docs/patterns/[surface]/CLAUDE.md ← surface rules
3. docs/patterns/[surface]/[pattern].md ← feature pattern (if exists)
4. packages/[component]/CLAUDE.md ← component rules
5. packages/[component]/src/[component].stories.tsx ← usage examples
```

---

## File 2 — Surface rules (`docs/patterns/[surface]/CLAUDE.md`)

### What it does

Defines interaction and visual rules that apply across **all** components when
building for this surface. These rules sit above component-level CLAUDE.md
files. When a conflict exists between a surface rule and a component rule, the
surface rule wins.

### What it must contain

Rules that are **cross-component** in nature — things that would otherwise be
decided inconsistently component by component. Examples from the internal admin
surface:

**Row interaction rules**

Whether a table row is clickable, and what that implies for hover state.
Connecting row clickability to the data model (does a detail page exist?) rather
than leaving it to the agent to infer:

```markdown
### Clickable rows

- If the PRD describes a detail page, record view, or drill-down → row is
  clickable
- If the PRD describes a read-only display with no destination → row is not
  clickable
- If unsure, default to clickable

### Hover state

- Row is clickable → hover state always applied
- Row is not clickable → hover state never applied, no exceptions
```

**Overflow menu rules**

A decision tree for when a row gets an overflow menu vs. an inline button vs.
nothing:

```markdown
Does the row have actions? No → no overflow menu, no action column Yes → how
many actions? 1 action + row is NOT clickable → inline button or icon 1 action +
row IS clickable → overflow menu 2+ actions → always overflow menu
```

**Badge and pill rules**

When to use a status badge, and how to map status values to visual tones.
Explicit tone definitions prevent the agent from inventing tones:

```markdown
- Positive / active / approved / complete → `positive`
- Warning / approaching limit / expiring → `caution`
- Critical / rejected / failed / overdue → `critical`
- Neutral / inactive / archived / unknown → `neutral`
- Pending / in review / awaiting approval → `pending`
```

### What it must NOT contain

- Component-specific implementation rules (those live in component CLAUDE.md)
- Rules that only apply to one feature type (those live in pattern files)
- Duplication of anything that already lives in a lower layer

---

## File 3 — Feature pattern file (`[surface]/[pattern].md`)

### What it does

Describes how to assemble a specific type of page or feature — which components
to use, in what order, with what configuration. It is a recipe, not a reference.

The agent reads this _after_ the surface rules and _before_ component docs.

### What it must contain

- **Component list** — the exact packages to use for this feature type
- **Assembly order** — the layout structure from outermost to innermost
- **Per-component configuration** — which props to set, what to avoid
- **A validation checklist** — the agent must run this before marking the task
  complete

Example structure for a list page:

```markdown
## Components required

- @spark-web/header
- @spark-web/table (Table, TableHeaderRow, TableHeaderCell, TableRow, TableCell)
- @spark-web/status-badge (if status column present)
- @spark-web/meatball (if row actions present)
- @spark-web/table (TablePagination, outside Table)

## Assembly order

1. Header
2. Table a. TableHeaderRow → TableHeaderCell (one per column) b. TableRow (one
   per record) → TableCell
3. TablePagination (sibling of Table, never inside it)

## Validation checklist

- [ ] Header has a title prop
- [ ] Hover state matches row clickability (see surface rules)
- [ ] Meatball only present when 2+ row actions exist
- [ ] Status cells use StatusBadge — no inline styling
- [ ] TablePagination is outside Table
```

---

## How this layer connects to the others

| Layer               | Reads from                      | Overrides                                |
| ------------------- | ------------------------------- | ---------------------------------------- |
| Root CLAUDE.md      | Nothing — entry point           | —                                        |
| Surface classifier  | Root (via reading order)        | —                                        |
| Surface rules       | Surface classifier              | Component defaults                       |
| Feature pattern     | Surface rules                   | Nothing — it assembles, doesn't override |
| Component CLAUDE.md | Feature pattern (per component) | Nothing for this surface                 |

---

## How to add a new surface

1. Create a folder at `docs/patterns/[surface-name]/`.
2. Create `CLAUDE.md` inside it with the surface rules (row behaviour, badge
   rules, any globally applicable interaction patterns).
3. Add a row to the signal table in `docs/patterns/CLAUDE.md` pointing to the
   new file.
4. Update the root `CLAUDE.md` if needed to note the new surface.
5. Create pattern files (list, form, detail, etc.) as features are designed.

Do not build for a surface until its rules file exists. An undefined surface
means the agent has no contract and will make assumptions.

---

## What happens if this layer is missing or incomplete

- The agent applies component defaults regardless of surface context — hover
  states, overflow menus, and badge tones become inconsistent across pages.
- Surface-level rules that conflict with component defaults are silently
  ignored.
- Two agents working on the same surface independently will produce different
  interaction patterns.
