# Institutional Memory-01 (`institutional-memory-01`) - SignalOS page block

> Three-view hypothesis history page (expandable grid, list, table) with parent-controlled view switching and an optional slot-based dialog.

- **Version:** 0.4.4
- **Kind:** block (group: institutional) · **Category:** pages
- **Install:** `npx shadcn@latest add @signalos/institutional-memory-01`
- **Registry dependencies (pulled automatically):** @signalos/tokens, @signalos/utils, @signalos/badge, @signalos/dialog, @signalos/table, @signalos/expandable-list, @signalos/page-header, @signalos/view-controler, @signalos/button, @signalos/card, @signalos/skeleton, @signalos/circular-progress, @signalos/activity-timeline, @signalos/data-table, @signalos/status-badge, @signalos/switch, @signalos/filter-toolbar, @signalos/metric-tile, @signalos/pagination
- **npm dependencies:** lucide-react@^1.7.0, @tanstack/react-table@^8.0.0
- **Files installed:** `src/components/blocks/institutional-memory-01/InstitutionalMemory01.tsx`, `src/components/blocks/institutional-memory-01/InstitutionalMemory01.types.ts`, `src/components/blocks/institutional-memory-01/InstitutionalMemory01.utils.ts`, `src/components/blocks/institutional-memory-01/InstitutionalMemory01.constants.ts`, `src/components/blocks/institutional-memory-01/components/DecisionLogDetailDialog.tsx`, `src/components/blocks/institutional-memory-01/components/DecisionLogSidebarPanels.tsx`, `src/components/blocks/institutional-memory-01/components/EvidenceCardWithClick.tsx`, `src/components/blocks/institutional-memory-01/components/FeedbackCard.tsx`, `src/components/blocks/institutional-memory-01/components/FeedbackError.tsx`, `src/components/blocks/institutional-memory-01/components/FeedbackTimeline.tsx`, `src/components/blocks/institutional-memory-01/components/HypothesisDecisionSearch.tsx`, `src/components/blocks/institutional-memory-01/components/SignalDetailMiniDialog.tsx`, `src/components/blocks/institutional-memory-01/components/SimilarDecisionsPanel.tsx`, `src/components/blocks/institutional-memory-01/components/TableView.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/institutional-memory-01
// mount the pulled page in a route, e.g. src/app/institutional/page.tsx
import InstitutionalMemory01 from "@/components/blocks/institutional-memory-01/InstitutionalMemory01"

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

## Props

### `InstitutionalMemory01View`

```ts
export type InstitutionalMemory01View = "grid" | "list" | "table"
```

### `Severity`

```ts
export type Severity = "info" | "low" | "medium" | "high" | "critical"
```

### `HypothesisStatus`

```ts
export type HypothesisStatus =
  "FORMING" | "SUFFICIENT" | "ROUTED" | "DECIDED" | "EXPIRED"
```

### `DecisionAction`

```ts
export type DecisionAction =
  "resolve" | "dismissed" | "escalate" | "schedule" | string
```

### `DecisionSearchMode`

```ts
export type DecisionSearchMode = "hybrid" | "vector" | "keyword"
```

### `FeedbackVote`

```ts
export type FeedbackVote = "agree" | "disagree" | "neutral"
```

### `EvidenceItem`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `type` | `string \| undefined` | no | - |  |
| `signal_id` | `string \| undefined` | no | - |  |
| `metric_id` | `string \| undefined` | no | - |  |
| `label` | `string \| undefined` | no | - |  |
| `baseline_id` | `string \| undefined` | no | - |  |
| `deviation_std` | `number \| undefined` | no | - |  |
| `source` | `string \| undefined` | no | - |  |

### `Signal`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `id` | `string` | yes | - |  |
| `signal_id` | `string` | yes | - |  |
| `domain` | `string` | yes | - |  |
| `cluster` | `string` | yes | - |  |
| `metric_id` | `string` | yes | - |  |
| `signal_type` | `string` | yes | - |  |
| `crlb_score` | `number` | yes | - |  |
| `initial_crlb_score` | `number` | yes | - |  |
| `reinforcement_term` | `number` | yes | - |  |
| `decay_lambda` | `number` | yes | - |  |
| `deviation_std` | `number` | yes | - |  |
| `source_connector_id` | `string \| null` | yes | - |  |
| `source_connector_type` | `string \| null` | yes | - |  |
| `severity` | `Severity` | yes | - |  |
| `payload` | `Record<string, unknown>` | yes | - |  |
| `observation_ids` | `string[]` | yes | - |  |
| `baseline_id` | `string \| null` | yes | - |  |
| `dimension_key` | `Record<string, unknown>` | yes | - |  |
| `target_roles` | `string[]` | yes | - |  |
| `tags` | `string[]` | yes | - |  |
| `embedding` | `number[] \| null` | yes | - |  |
| `fired_at` | `string` | yes | - |  |
| `expires_at` | `string \| null` | yes | - |  |
| `status` | `"active" \| "decayed"` | yes | - |  |
| `confidence_current` | `number` | yes | - |  |

### `Hypothesis`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `id` | `string` | yes | - |  |
| `label` | `string` | yes | - |  |
| `description` | `string` | yes | - |  |
| `domain` | `string` | yes | - |  |
| `cluster` | `string` | yes | - |  |
| `signal_ids` | `string[]` | yes | - |  |
| `cagg` | `number` | yes | - |  |
| `sufficiency_score` | `number` | yes | - |  |
| `evidence` | `EvidenceItem[]` | yes | - |  |
| `routed` | `boolean` | yes | - |  |
| `routed_to` | `string \| null` | yes | - |  |
| `status` | `HypothesisStatus` | yes | - |  |
| `created_at` | `string` | yes | - |  |
| `updated_at` | `string` | yes | - |  |
| `confidence_initial` | `number` | yes | - |  |
| `decay_lambda` | `number` | yes | - |  |
| `severity` | `Severity` | yes | - |  |
| `target_roles` | `string[]` | yes | - |  |
| `suggested_actions` | `string[]` | yes | - |  |
| `tags` | `string[]` | yes | - |  |
| `decayed_at` | `string \| null` | yes | - |  |
| `expire_reason` | `string \| null` | yes | - |  |
| `confidence_current` | `number` | yes | - |  |
| `refined_by_llm` | `boolean \| undefined` | no | - |  |
| `refinement_confidence` | `number \| null \| undefined` | no | - |  |
| `refinement_reasoning` | `string \| null \| undefined` | no | - |  |
| `refinement_dropped_signal_ids` | `string[] \| null \| undefined` | no | - |  |
| `refinement_dropped_reasoning` | `Record<string, unknown> \| null \| undefined` | no | - |  |
| `refinement_model` | `string \| null \| undefined` | no | - |  |
| `act_by_deadline` | `string \| null \| undefined` | no | - |  |
| `act_by_source` | `string \| null \| undefined` | no | - |  |
| `act_by_reason` | `string \| null \| undefined` | no | - |  |
| `act_by_confidence` | `number \| null \| undefined` | no | - |  |

### `Decision`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `id` | `string` | yes | - |  |
| `hypothesis_id` | `string` | yes | - |  |
| `action` | `string` | yes | - |  |
| `rationale` | `string` | yes | - |  |
| `resolution` | `string \| null` | yes | - |  |
| `expected_outcome` | `string` | yes | - |  |
| `expected_outcome_by` | `string` | yes | - |  |
| `decided_at` | `string` | yes | - |  |
| `confidence_at_decision` | `number` | yes | - |  |
| `priority_score_at_decision` | `number` | yes | - |  |
| `role` | `string \| null` | yes | - |  |
| `user_id` | `string` | yes | - |  |
| `dismiss_reason` | `string \| null` | yes | - |  |

### `DecisionLogEventType`

```ts
export type DecisionLogEventType =
  | "hypothesis.created"
  | "hypothesis.routed"
  | "hypothesis.expired"
  | "signal.fired"
  | "decision.created"
  | "feedback.submitted"
  | string
```

### `DecisionLogEvent`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `event_type` | `string` | yes | - |  |
| `occurred_at` | `string` | yes | - |  |
| `actor_id` | `string \| null` | yes | - |  |
| `summary` | `string` | yes | - |  |
| `payload` | `Record<string, unknown>` | yes | - |  |

### `DecisionLogGroup`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `hypothesis` | `Hypothesis` | yes | - |  |
| `events` | `DecisionLogEvent[]` | yes | - |  |

### `HypothesisFeedback`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `id` | `string` | yes | - |  |
| `hypothesis_id` | `string` | yes | - |  |
| `user_id` | `string` | yes | - |  |
| `feedback_text` | `string` | yes | - |  |
| `vote` | `FeedbackVote` | yes | - |  |
| `created_at` | `string` | yes | - |  |
| `updated_at` | `string` | yes | - |  |

### `DecisionSearchResult`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `id` | `string` | yes | - |  |
| `hypothesis_id` | `string \| null \| undefined` | no | - |  |
| `hypothesis_label` | `string \| null \| undefined` | no | - |  |
| `user_id` | `string \| null \| undefined` | no | - |  |
| `role` | `string \| null \| undefined` | no | - |  |
| `action` | `string \| null \| undefined` | no | - |  |
| `status` | `string \| null \| undefined` | no | - |  |
| `rationale` | `string \| null \| undefined` | no | - |  |
| `expected_outcome` | `string \| null \| undefined` | no | - |  |
| `resolution` | `string \| null \| undefined` | no | - |  |
| `dismiss_reason` | `string \| null \| undefined` | no | - |  |
| `confidence_at_decision` | `number \| null \| undefined` | no | - |  |
| `priority_score_at_decision` | `number \| null \| undefined` | no | - |  |
| `decided_at` | `string \| null \| undefined` | no | - |  |
| `score` | `number \| null \| undefined` | no | - |  |
| `vec_similarity` | `number \| null \| undefined` | no | - |  |
| `keyword_rank` | `number \| null \| undefined` | no | - |  |

### `SimilarDecision`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `id` | `string` | yes | - |  |
| `hypothesis_id` | `string \| null \| undefined` | no | - |  |
| `hypothesis_label` | `string \| null \| undefined` | no | - |  |
| `action` | `string \| null \| undefined` | no | - |  |
| `status` | `string \| null \| undefined` | no | - |  |
| `rationale` | `string \| null \| undefined` | no | - |  |
| `resolution` | `string \| null \| undefined` | no | - |  |
| `decided_at` | `string \| null \| undefined` | no | - |  |
| `vec_similarity` | `number` | yes | - |  |

### `PaginationConfig`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `page` | `number` | yes | - |  |
| `pageSize` | `number` | yes | - |  |
| `total` | `number` | yes | - |  |
| `totalPages` | `number` | yes | - |  |
| `pageSizeOptions` | `number[] \| undefined` | no | - |  |
| `onPageChange` | `(page: number) => void` | yes | - |  |
| `onPageSizeChange` | `(pageSize: number) => void` | yes | - |  |

### `DecisionLogDetailDialogProps`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `group` | `DecisionLogGroup \| null` | yes | - |  |
| `open` | `boolean` | yes | - |  |
| `onOpenChange` | `(open: boolean) => void` | yes | - |  |
| `decisions` | `Decision[] \| undefined` | no | - |  |
| `feedback` | `HypothesisFeedback[] \| undefined` | no | - |  |
| `signals` | `Signal[] \| undefined` | no | - |  |
| `searchResults` | `DecisionSearchResult[] \| undefined` | no | - |  |
| `searchTotal` | `number \| undefined` | no | - |  |
| `isSearching` | `boolean \| undefined` | no | - |  |
| `searchError` | `string \| undefined` | no | - |  |
| `onSearch` | `((query: string, mode: DecisionSearchMode) => void) \| undefined` | no | - |  |
| `onSearchReset` | `(() => void) \| undefined` | no | - |  |
| `similarDecisions` | `SimilarDecision[] \| undefined` | no | - |  |
| `isSimilarLoading` | `boolean \| undefined` | no | - |  |
| `similarError` | `string \| undefined` | no | - |  |

### `DecisionLogSummary`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `total_hypotheses` | `number` | yes | - |  |
| `needs_routing` | `number` | yes | - |  |
| `high_severity` | `number` | yes | - |  |
| `deadline_within_24h` | `number` | yes | - |  |

### `DecisionLogSortByFilter`

```ts
export type DecisionLogSortByFilter =
  "newest" | "urgency" | "deadline" | "confidence" | "severity"
```

### `DecisionLogSeverityFilter`

```ts
export type DecisionLogSeverityFilter = "high" | "medium" | "low" | ""
```

### `DecisionLogDeadlineFilter`

```ts
export type DecisionLogDeadlineFilter = "24" | "48" | "72" | ""
```

### `DecisionLogMetricFilter`

```ts
export type DecisionLogMetricFilter =
  "total_hypotheses" | "needs_routing" | "high_severity" | "deadline_within_24h"
```

### `InstitutionalMemory01Filters`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `search` | `string \| undefined` | no | - |  |
| `sortBy` | `DecisionLogSortByFilter \| undefined` | no | - |  |
| `severity` | `DecisionLogSeverityFilter \| undefined` | no | - |  |
| `deadline` | `DecisionLogDeadlineFilter \| undefined` | no | - |  |

### `InstitutionalMemory01Props`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `entries` | `DecisionLogGroup[]` | yes | - | Hypothesis groups to display, each pairing a hypothesis with its event log. |
| `view` | `InstitutionalMemory01View` | yes | - | Currently active view mode. Controlled by the parent. |
| `onViewChange` | `(view: InstitutionalMemory01View) => void` | yes | - | Called when the user switches view mode. |
| `isLoading` | `boolean \| undefined` | no | - | When true, the list and metric tiles render in a loading skeleton state. |
| `pagination` | `PaginationConfig` | yes | - | Pagination state and handlers. Always required — pass a no-op config when pagination is not needed. |
| `dialog` | `DecisionLogDetailDialogProps \| undefined` | no | - | Props for the optional detail dialog. Omit to disable the dialog entirely. |
| `onViewDetail` | `((group: DecisionLogGroup) => void) \| undefined` | no | - | Called when the user activates "view detail" on a hypothesis row. Omit to hide the affordance. |
| `decisionsMap` | `Record<string, Decision[]> \| undefined` | no | - | Per-hypothesis decisions, keyed by hypothesis id. Managed by the container. |
| `onExpand` | `((hypothesisId: string) => void) \| undefined` | no | - | Called when a hypothesis row is expanded; container should fetch and store decisions. |
| `title` | `string \| undefined` | no | `"Institutional Memory"` | Page heading. |
| `description` | `string \| undefined` | no | - | Subheading shown below the title. |
| `tableData` | `ColumnDef<DecisionLogGroup, unknown>[]` | yes | - | Column definitions for the table view. Required even if the table view is not the default. |
| `summary` | `DecisionLogSummary \| null` | yes | - | Metric tile summary values. Pass null to render tiles in loading state. |
| `filters` | `InstitutionalMemory01Filters \| undefined` | no | - | Current toolbar filter values. Only include fields you want to control. |
| `onFiltersChange` | `((patch: Partial<InstitutionalMemory01Filters>) => void) \| undefined` | no | - | Called with a partial patch whenever the user changes a filter. Merging is the container's responsibility. |
| `onRefresh` | `(() => void) \| undefined` | no | - | Called when the user clicks the refresh button in the toolbar. Omit to hide the button. |
| `isRefreshing` | `boolean \| undefined` | no | - | When true, the refresh button shows a spinner. |
| `filterSelects` | `readonly FilterSelectGroup[] \| undefined` | no | - | Generic select dropdowns injected by the parent (e.g. owner, status). |
| `activeMetric` | `DecisionLogMetricFilter \| null \| undefined` | no | - | Currently active metric tile filter (null = no filter). |
| `onMetricClick` | `((metric: DecisionLogMetricFilter \| null) => void) \| undefined` | no | - | Called when a metric tile is clicked; container fetches filtered data. |
| `toolbarExtras` | `ReactNode` | no | - | Additional content rendered inside the FilterToolbar (e.g. action buttons, toggles, badges). |

## Changelog

## 0.4.4

- Initial full implementation: `InstitutionalMemory01` block with `DecisionLogDetailDialog`, `DecisionLogSidebarPanels`, `FeedbackTimeline`, `FeedbackCard`, `FeedbackError`, `EvidenceCardWithClick`, `HypothesisDecisionSearch`, `SignalDetailMiniDialog`, `SimilarDecisionsPanel`, and `TableView` subcomponents.
- Add `DecisionLogEvent` / `DecisionLogEventType` types and `events`, `act_by_reason`, `act_by_deadline` fields to `InstitutionalMemory01.types.ts`.

## 0.4.3

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

# institutional-memory-01

## 0.4.2

- Replace raw scale tokens with semantic tokens.


## 0.4.1

- Updated component content.

## 0.4.0

- Wire `onMetricClick` and `activeMetric` props to MetricTile onClick handlers; metric tiles now toggle the active filter correctly instead of doing nothing.
- Fix dead `onViewDetail` fallbacks in grid and list views — affordance is now hidden (passes `undefined`) when the callback is not provided.
- Fix `TableView` pagination type mismatch: local `PaginationConfig` with `onRowsPerPageChange` replaced by the shared type from `InstitutionalMemory01.types.ts` (`onPageSizeChange`); page-size changes now reach `DataTable`.
- Replace all raw Tailwind palette classes in `InstitutionalMemory01.utils.ts` (`bg-red-600/15`, `text-red-500`, `bg-amber-500/20`, `text-success-500`, `bg-error-500`, etc.) with semantic tokens (`bg-bg-error`, `text-text-error`, `bg-bg-warning`, `text-text-warning`, `text-text-success`, `bg-status-error`, `bg-status-warning`).
- Remove duplicate inline constant arrays from `InstitutionalMemory01.tsx`; import `SORT_BY_OPTIONS`, `SEVERITY_OPTIONS`, `DEADLINE_OPTIONS` from `InstitutionalMemory01.constants.ts`. Add `InstitutionalMemory01.constants.ts` to shipped `files[]`.
- Add JSDoc to all previously undocumented props in `InstitutionalMemory01Props`.
- Expand test suite: add coverage for `isLoading` state, `onFiltersChange`, `onRefresh`, `onMetricClick` fire, and `onMetricClick` toggle-off.

## 0.3.4

- Unit test case issue fix


## 0.3.3

- Added `@signalos/switch` registry dependency; preview toolbar uses Switch component.

## 0.3.1

- Refactored to fully presentational: block now accepts `entries: DecisionLogGroup[]` instead of `ExpandableListDefaultItem[]`, converting to list items internally.
- All API types (blackboard, hypothesis, signal, decision, feedback, search) moved into `InstitutionalMemory01.types.ts`; removed all backend/Redux dependencies.
- `DecisionLogDetailDialog` receives all data via props: `decisions`, `feedback`, `signals`, `searchResults`, `similarDecisions`, and loading/error states.
- `HypothesisDecisionSearch` manages its own input/mode state; fires `onSearch`/`onReset` callbacks to parent.
- `SimilarDecisionsPanel` is now fully prop-driven (`results`, `isLoading`, `error`).
- `EvidenceCardWithClick` accepts `signal` prop directly instead of reading from a Redux selector.
- `FeedbackCard` / `HypothesisFeedbackPanel` removed `hypothesisId` requirement; accepts `decisions` array only.
- Removed `ScrollArea` dependency (replaced with native overflow scroll); no new registry deps added.
- `InstitutionalMemory01.utils.ts` no longer imports backend types; severity helpers are self-contained.
- Preview updated with realistic mock `DecisionLogGroup` data.

## 0.2.0

- Refactored to be fully prop-driven: items, view, onViewChange, onViewDetail, and dialog all passed from parent.
- Added list view (simple bordered rows with category/severity badges).
- Added table view (ID, title, category, severity, status columns).
- Added parent-controlled slot-based dialog (open, onOpenChange, title, ReactNode content).
- Extracted InstitutionalMemory01.types.ts with typed interfaces for all props.

## 0.1.0

- Initial release: centered-card sign-in page composed from @signalos primitives
  (input, label, checkbox, button) with error/loading states and brand/footer slots.
