# Signal Rules (`signal-rules-01`) - SignalOS page block

> Full-page signal rule review block with a queue, detail panel, and add-rule dialog.

- **Version:** 0.3.0
- **Kind:** block (group: semantics-details) · **Category:** pages
- **Install:** `npx shadcn@latest add @signalos/signal-rules-01`
- **Registry dependencies (pulled automatically):** @signalos/tokens, @signalos/utils, @signalos/badge, @signalos/button, @signalos/command, @signalos/form-dialog, @signalos/text-field, @signalos/popover, @signalos/select, @signalos/textarea, @signalos/tooltip, @signalos/equilibrium-01, @signalos/split-panel, @signalos/page-header, @signalos/input, @signalos/label, @signalos/dialog
- **npm dependencies:** lucide-react@^1.7.0
- **Files installed:** `src/components/blocks/signal-rules-01/SignalRules.tsx`, `src/components/blocks/signal-rules-01/components/SignalRuleAddDialog.tsx`, `src/components/blocks/signal-rules-01/SignalRules.types.ts`, `src/components/blocks/signal-rules-01/components/SignalRuleQueue.tsx`, `src/components/blocks/signal-rules-01/components/SignalRuleDetail.tsx`, `src/components/blocks/signal-rules-01/components/RuleReadView.tsx`, `src/components/blocks/signal-rules-01/components/RuleEditView.tsx`, `src/components/blocks/signal-rules-01/components/EditConditionRow.tsx`

## Access

This is a private registry: pulling source requires a `SIGNALOS_REGISTRY_TOKEN`
(GitHub fine-grained PAT with read access to the signal-widgets repo) and an
`@signalos` entry in components.json `"registries"`. Previews and this document are public.

## Usage

```tsx
// after: npx shadcn@latest add @signalos/signal-rules-01
// mount the pulled page in a route, e.g. src/app/semantics-details/page.tsx
import SignalRules from "@/components/blocks/signal-rules-01/SignalRules"

export default function Page() {
  return <SignalRules />
}
```

## Props

### `SignalRuleDirection`

```ts
export type SignalRuleDirection = "above" | "below" | "any"
```

### `SignalRuleCondition`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `direction` | `SignalRuleDirection` | yes | - |  |
| `metric_patterns` | `string[]` | yes | - |  |

### `SignalRule`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `id` | `string` | yes | - |  |
| `name` | `string` | yes | - |  |
| `description` | `string` | yes | - |  |
| `boost` | `number` | yes | - |  |
| `confidence` | `number` | yes | - |  |
| `time_window_hours` | `number` | yes | - |  |
| `conditions` | `SignalRuleCondition[]` | yes | - |  |
| `review_origin` | `string \| null \| undefined` | no | - |  |

### `SignalRulesArtifact`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `rules` | `SignalRule[]` | yes | - |  |

### `SignalRuleReviewItem`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `index` | `number` | yes | - |  |
| `status` | `"accepted" \| "flagged" \| "deleted"` | yes | - |  |
| `feedback` | `string` | yes | - |  |
| `edits` | `Partial<Pick<SignalRule, "name" \| "description" \| "confidence" \| "boost" \| "time_window_hours"> & { conditions: SignalRuleCondition[]; }>` | yes | - |  |
| `connector_id` | `string \| undefined` | no | - |  |
| `item_id` | `string \| undefined` | no | - |  |

### `MetricDirection`

```ts
export type MetricDirection = "up_is_good" | "down_is_good" | "neutral"
```

### `MetricCatalogEntry`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `display_name` | `string \| null \| undefined` | no | - |  |
| `description` | `string \| null \| undefined` | no | - |  |
| `direction` | `MetricDirection \| null \| undefined` | no | - |  |
| `unit` | `string \| null \| undefined` | no | - |  |
| `connector_id` | `string \| null \| undefined` | no | - |  |
| `source_cluster` | `string \| null \| undefined` | no | - |  |
| `is_cross_source` | `boolean \| null \| undefined` | no | - |  |
| `source_entities` | `string[] \| null \| undefined` | no | - |  |
| `sql_logic` | `string \| null \| undefined` | no | - |  |

### `MetricCatalog`

```ts
export type MetricCatalog = Record<string, MetricCatalogEntry>
```

### `SubmitSignalRulesReviewPayload`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `action` | `"confirm" \| "retry"` | yes | - |  |
| `items` | `SignalRuleReviewItem[] \| undefined` | no | - |  |

### `SignalRuleItemEdits`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `id` | `string \| undefined` | no | - |  |
| `name` | `string` | yes | - |  |
| `description` | `string` | yes | - |  |
| `boost` | `number` | yes | - |  |
| `confidence` | `number` | yes | - |  |
| `time_window_hours` | `number` | yes | - |  |
| `conditions` | `SignalRuleCondition[]` | yes | - |  |

### `AddSignalRulePayload`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `action` | `"add_item" \| "improve_new_item"` | yes | - |  |
| `feedback` | `string \| undefined` | no | - |  |
| `item_edits` | `SignalRuleItemEdits` | yes | - |  |
| `connector_id` | `string \| undefined` | no | - |  |

### `AddSignalRuleResponse`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `status` | `string \| undefined` | no | - |  |
| `item` | `SignalRule \| undefined` | no | - |  |
| `soft_warning` | `string \| undefined` | no | - |  |

## Changelog

## 0.3.0

- Decompose `SignalRules` into `EditConditionRow`, `RuleEditView`, `RuleReadView`, `SignalRuleAddDialog`, `SignalRuleDetail`, and `SignalRuleQueue` subcomponents under `components/`.
- Add `EditConditionRow` with multi-select popover for condition field values; wire `getMetricConnectorId` and `MetricInfoButton` from `equilibrium-01`.

## 0.2.10

- Replace raw scale token classes with semantic tokens (text-text-error, bg-bg-success, border-border-warning, etc.) to respect client theme overrides.

## 0.2.9

- Fix cross-item imports to use canonical @/components paths; add missing signalos.category to manifests.

## 0.2.8

- `SignalRules`: remove `metricPickerOpen` and `onMetricPickerChange` props (metric picker open state is now internal to `SignalRuleDetail`).
- `SignalRules`: remove `addMetricPickerOpen` and `onAddDialogMetricPickerChange` props (add-dialog picker state is now internal to `SignalRuleAddDialog`).
- `SignalRules`: add `SplitPanelListHeader` import; expose `onImproveWithAi` callback (was previously commented out).
- `SignalRules`: rename confirm button `data-testid` from `signal-rules-confirm-button` to `signal-rules-submit-button`.
- `SignalRules`: update header description — remove "AI-generated" qualifier.
- `SignalRules`: move confirmed banner outside `PageHeader` with updated border/background tokens; remove `CheckCircle2` icon.
- `SignalRules.types.ts`: define `MetricCatalog` and `MetricCatalogEntry` locally; remove import from `metrics-01`.
- Remove `@signalos/metrics-01` from `registryDependencies`.

## 0.2.7

- Replace raw Dialog/DialogFooter with FormDialog in SignalRuleAddDialog; custom footer carries error banner + cancel/save buttons.
- Replace Label + Input for Name and Time Window fields with TextField widget; Description textarea keeps inline label + aria-invalid pattern.
- Swap `@signalos/dialog`, `@signalos/input`, `@signalos/label` → `@signalos/form-dialog`, `@signalos/text-field` in registryDependencies.

## 0.2.5

- Content updates.

## 0.2.4

- Content updates.

## 0.2.1
## 0.2.0

- Replace desktop `lg:grid-cols-12` layout with `SplitPanel` widget for the queue/detail split.
- Mobile tab-switcher layout unchanged; `SplitPanel` is shown only on `lg:` and above.
- Add `@signalos/split-panel` to `registryDependencies`.

## 0.1.0
