# 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.5.4
- **Kind:** block (group: institutional) · **Category:** pages
- **Install:** `npx shadcn@4.1.2 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, @signalos/dropdown-menu, @signalos/textarea, @signalos/tooltip, @signalos/combobox, @signalos/data-primitives, @signalos/input, @signalos/scroll-area
- **npm dependencies:** lucide-react@^1.7.0, @tanstack/react-table@^8.0.0, react-markdown@^9.0.3, echarts@^6.1.0, echarts-for-react@^3.0.7
- **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/DecisionLogDetailHeader.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`, `src/components/blocks/institutional-memory-01/components/linkage/DecisionLinkagePanel.tsx`, `src/components/blocks/institutional-memory-01/components/linkage/DecisionLinkagePanel.constants.ts`, `src/components/blocks/institutional-memory-01/components/linkage/DecisionLinkagePanel.utils.ts`, `src/components/blocks/institutional-memory-01/components/linkage/CandidateList.tsx`, `src/components/blocks/institutional-memory-01/components/linkage/CandidatePickerDialog.tsx`, `src/components/blocks/institutional-memory-01/components/linkage/FeatureVector.tsx`, `src/components/blocks/institutional-memory-01/components/linkage/VerdictForm.tsx`, `src/components/blocks/institutional-memory-01/components/linkage/InlineNotice.tsx`, `src/components/blocks/institutional-memory-01/components/chat/HypothesisChat.tsx`, `src/components/blocks/institutional-memory-01/components/chat/HypothesisChat.constants.ts`, `src/components/blocks/institutional-memory-01/components/chat/SectionHeading.tsx`, `src/components/blocks/institutional-memory-01/components/chat/ChatInput.tsx`, `src/components/blocks/institutional-memory-01/components/chat/ChatMessageBubble.tsx`, `src/components/blocks/institutional-memory-01/components/chat/ChatSuggestions.tsx`, `src/components/blocks/institutional-memory-01/components/chat/ChatSuggestions.utils.ts`, `src/components/blocks/institutional-memory-01/components/chat/ChatThinkingTrace.tsx`, `src/components/blocks/institutional-memory-01/components/chat/ChatVisualization.tsx`, `src/components/blocks/institutional-memory-01/components/Recall/index.ts`, `src/components/blocks/institutional-memory-01/components/Recall/RecallPanel.tsx`, `src/components/blocks/institutional-memory-01/components/Recall/RecallSection.tsx`, `src/components/blocks/institutional-memory-01/components/Recall/RecallDialog.tsx`, `src/components/blocks/institutional-memory-01/components/Recall/RecallExportPanels.tsx`, `src/components/blocks/institutional-memory-01/components/Recall/RecallSummaryChip.tsx`, `src/components/blocks/institutional-memory-01/components/Recall/PrecedentCard.tsx`, `src/components/blocks/institutional-memory-01/components/Recall/PrecedentDetail.tsx`, `src/components/blocks/institutional-memory-01/components/Recall/OpenDecisionCard.tsx`, `src/components/blocks/institutional-memory-01/components/Recall/FeatureMeter.tsx`, `src/components/blocks/institutional-memory-01/components/Recall/recall-utils.ts`

## 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@4.1.2 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 | - |  |

### `LinkableDecision`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `id` | `string` | yes | - |  |
| `action` | `string \| null \| undefined` | no | - |  |
| `decided_at` | `string \| null \| undefined` | no | - |  |
| `actual_outcome` | `string \| null \| undefined` | no | - |  |
| `reward` | `number \| null \| undefined` | no | - |  |
| `status` | `string \| null \| undefined` | no | - |  |

### `OutcomeApiError`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `kind` | `"outage" \| "refused" \| "absent" \| "unknown"` | yes | - |  |
| `detail` | `string` | yes | - |  |

### `DecisionLinkState`

```ts
export type DecisionLinkState =
  | "UNLINKED"
  | "PENDING_CREATION"
  | "BOUND"
  | "ABSTAINED"
  | "FALSE_ALARM"
  | "NO_RECORD"
```

### `CandidateFeaturesLike`

```ts
export type CandidateFeaturesLike = Record<string, number | null | undefined>
```

### `LinkCandidateLike`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `record_key` | `string` | yes | - |  |
| `title` | `string \| null \| undefined` | no | - |  |
| `description` | `string \| null \| undefined` | no | - |  |
| `status` | `string \| null \| undefined` | no | - |  |
| `score` | `number \| null` | yes | - |  |
| `opened_at` | `string \| null \| undefined` | no | - |  |
| `resolved_at` | `string \| null \| undefined` | no | - |  |
| `gate_failure` | `string \| null \| undefined` | no | - |  |
| `features` | `CandidateFeaturesLike \| null \| undefined` | no | - |  |

### `DecisionLinkLike`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `state` | `DecisionLinkState` | yes | - |  |
| `record_key` | `string \| null \| undefined` | no | - |  |
| `sor_table` | `string \| null \| undefined` | no | - |  |
| `sor_schema` | `string \| null \| undefined` | no | - |  |
| `bound_by` | `string \| null \| undefined` | no | - |  |
| `bound_at` | `string \| null \| undefined` | no | - |  |
| `watch_expires_at` | `string \| null \| undefined` | no | - |  |
| `time_bounded` | `boolean \| undefined` | no | - |  |
| `features` | `CandidateFeaturesLike \| null \| undefined` | no | - |  |

### `DecisionLinkScanLike`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `action` | `string` | yes | - |  |
| `reason` | `string \| null \| undefined` | no | - |  |
| `margin` | `number \| null \| undefined` | no | - |  |
| `proposed_key` | `string \| null \| undefined` | no | - |  |
| `window_start` | `string \| null \| undefined` | no | - |  |
| `window_end` | `string \| null \| undefined` | no | - |  |

### `DecisionLinkVerdict`

```ts
export type DecisionLinkVerdict =
  "bind" | "rebind" | "pending" | "not_real" | "no_record" | "abstain"
```

### `DecisionLinkRecordOption`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `key` | `string` | yes | - |  |
| `title` | `string \| null` | yes | - |  |
| `score` | `number \| null` | yes | - |  |
| `gate` | `string \| null` | yes | - |  |

### `DecisionLinkageLinkProps`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `href` | `string` | yes | - |  |
| `className` | `string \| undefined` | no | - |  |
| `children` | `ReactNode` | yes | - |  |

### `DecisionLinkageProps`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `decisions` | `LinkableDecision[]` | yes | - | Decisions taken on the current hypothesis; the panel renders nothing meaningful when empty. |
| `selectedDecisionId` | `string \| null \| undefined` | no | - | The decision currently being adjudicated. Falls back to the first decision when omitted or stale. |
| `onSelectDecision` | `((decisionId: string) => void) \| undefined` | no | - | Called when the user switches which decision is being adjudicated. |
| `link` | `DecisionLinkLike \| null \| undefined` | no | - | The existing link for the selected decision, if any. |
| `isLinkLoading` | `boolean \| undefined` | no | - |  |
| `linkError` | `OutcomeApiError \| null \| undefined` | no | - |  |
| `scan` | `DecisionLinkScanLike \| null \| undefined` | no | - | The most recent scan result for the selected decision. |
| `isScanLoading` | `boolean \| undefined` | no | - |  |
| `scanError` | `OutcomeApiError \| null \| undefined` | no | - |  |
| `onScan` | `(() => void) \| undefined` | no | - | Called to (re)scan the client's records for candidates. Omit to hide the control. |
| `scoredCandidates` | `LinkCandidateLike[] \| undefined` | no | - | Ranked candidates from the scan. |
| `gatedCandidates` | `LinkCandidateLike[] \| undefined` | no | - | Candidates the scan excluded before scoring. |
| `selectedCandidate` | `LinkCandidateLike \| null \| undefined` | no | - | The candidate currently selected in the verdict form, if resolvable from `scoredCandidates`/`gatedCandidates`. |
| `isAbstaining` | `boolean \| undefined` | no | - | True when the automatic scan abstained rather than proposing a candidate. |
| `needsConfiguration` | `boolean \| undefined` | no | - | True when this decision's pipeline has no system of record configured. |
| `hasScanned` | `boolean \| undefined` | no | - | True once a scan has completed at least once for the selected decision. |
| `isSettled` | `boolean \| undefined` | no | - | True once the link and scan requests have both settled (success or error). |
| `onPickCandidate` | `((recordKey: string) => void) \| undefined` | no | - | Called when the user picks a candidate, from either the best-match tile or the picker dialog. |
| `verdict` | `DecisionLinkVerdict \| undefined` | no | - | Verdict form state, fully controlled by the caller. |
| `onVerdictChange` | `((verdict: DecisionLinkVerdict) => void) \| undefined` | no | - |  |
| `recordKey` | `string \| undefined` | no | - |  |
| `onRecordKeyChange` | `((value: string) => void) \| undefined` | no | - |  |
| `note` | `string \| undefined` | no | - |  |
| `onNoteChange` | `((value: string) => void) \| undefined` | no | - |  |
| `recordOptions` | `DecisionLinkRecordOption[] \| undefined` | no | - | The records the scan returned, which are the only bindable ones. |
| `canSubmitVerdict` | `boolean \| undefined` | no | - |  |
| `isSubmittingVerdict` | `boolean \| undefined` | no | - |  |
| `verdictError` | `OutcomeApiError \| null \| undefined` | no | - |  |
| `isAlreadySettledError` | `boolean \| undefined` | no | - |  |
| `lastVerdictAt` | `string \| null \| undefined` | no | - |  |
| `onSubmitVerdict` | `(() => void) \| undefined` | no | - | Called when the user submits the verdict form. |
| `LinkComponent` | `ComponentType<DecisionLinkageLinkProps> \| undefined` | no | - | Renders the "Configure" link when a pipeline has no system of record. Omit to render plain text instead of a link. |
| `systemOfRecordSettingsHref` | `string \| undefined` | no | - |  |
| `className` | `string \| undefined` | no | - |  |

### `ChatRole`

```ts
export type ChatRole = "human" | "ai"
```

### `ChatVisualizationLike`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `chart_type` | `string` | yes | - |  |
| `chart_json` | `Record<string, unknown>` | yes | - |  |
| `chart_insights` | `string \| null \| undefined` | no | - |  |

### `ChatMessage`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `role` | `ChatRole` | yes | - |  |
| `content` | `string` | yes | - |  |
| `visualization` | `ChatVisualizationLike \| null \| undefined` | no | - |  |

### `ChatThinkingStep`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `step` | `number` | yes | - |  |
| `toolName` | `string` | yes | - |  |
| `status` | `"done" \| "pending"` | yes | - |  |
| `inference` | `string \| null \| undefined` | no | - |  |

### `ChatTurnMeta`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `elapsedMs` | `number` | yes | - |  |
| `totalSteps` | `number` | yes | - |  |

### `ChatSuggestion`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `id` | `string` | yes | - |  |
| `label` | `string` | yes | - | Short category chip, e.g. "Evidence". |
| `question` | `string` | yes | - |  |

### `HypothesisChatProps`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `messages` | `ChatMessage[]` | yes | - |  |
| `sessionTitle` | `string \| null \| undefined` | no | - |  |
| `historyLoading` | `boolean \| undefined` | no | - |  |
| `historyError` | `string \| null \| undefined` | no | - |  |
| `isStreaming` | `boolean \| undefined` | no | - |  |
| `statusMessage` | `string \| null \| undefined` | no | - |  |
| `thinkingSteps` | `ChatThinkingStep[] \| undefined` | no | - |  |
| `lastTurnMeta` | `ChatTurnMeta \| null \| undefined` | no | - |  |
| `streamError` | `string \| null \| undefined` | no | - |  |
| `onSendQuestion` | `(question: string) => void` | yes | - |  |
| `suggestions` | `ChatSuggestion[] \| undefined` | no | - | Suggested questions offered on an empty thread and as follow-ups. Product copy - pass the caller's own set. |
| `emptySuggestionCount` | `number \| undefined` | no | `5` | Number of suggestions to show on an empty thread. |
| `followUpSuggestionCount` | `number \| undefined` | no | `3` | Number of suggestions to show as follow-up chips once a thread has messages. |
| `isDarkMode` | `boolean \| undefined` | no | `false` | Renders chart/table/KPI payloads in dark colors. Pass the app's own dark-mode state - the panel does not detect theme itself. |
| `className` | `string \| undefined` | no | - |  |

### `RecallPrecedentFeaturesLike`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `relevance` | `number` | yes | - |  |
| `recency` | `number` | yes | - |  |
| `outcome_quality` | `number` | yes | - |  |
| `evidence` | `number` | yes | - |  |
| `reliability` | `number \| undefined` | no | - | Source-trust weight. Present only for some sources. |

### `RecallHypothesisSnapshotLike`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `label` | `string` | yes | - |  |
| `description` | `string \| null \| undefined` | no | - |  |
| `hypothesis_id` | `string \| null \| undefined` | no | - | Present when the originating hypothesis can still be drilled into. |
| `source_connection_ids` | `string[]` | yes | - |  |

### `RecallPrecedentLike`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `id` | `string` | yes | - |  |
| `score` | `number` | yes | - |  |
| `similarity` | `number \| null` | yes | - | Cosine similarity (0..1), or null for a keyword-only hit. |
| `created_at` | `string \| null \| undefined` | no | - |  |
| `action` | `string \| null \| undefined` | no | - |  |
| `reinforcement_value` | `number` | yes | - | Positive = worked, negative = backfired, zero = neutral. |
| `outcome_observed` | `boolean` | yes | - |  |
| `outcome_notes` | `string \| null \| undefined` | no | - |  |
| `signal_types` | `string[]` | yes | - |  |
| `domain_tags` | `string[]` | yes | - |  |
| `features` | `RecallPrecedentFeaturesLike` | yes | - |  |
| `decision_id` | `string \| null \| undefined` | no | - |  |
| `hypothesis_snapshot` | `RecallHypothesisSnapshotLike` | yes | - |  |

### `RecallOpenDecisionLike`

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

### `RecallSummaryLike`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `total` | `number` | yes | - |  |
| `worked` | `number` | yes | - |  |
| `backfired` | `number` | yes | - |  |
| `neutral` | `number` | yes | - |  |
| `avg_reward` | `number` | yes | - |  |
| `top_positive_action` | `string \| null \| undefined` | no | - |  |

### `RecallResult`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `precedents` | `RecallPrecedentLike[]` | yes | - |  |
| `open_decisions` | `RecallOpenDecisionLike[]` | yes | - |  |
| `summary` | `RecallSummaryLike \| null` | yes | - |  |

### `RecallPanelProps`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `hypothesisId` | `string \| null` | yes | - |  |
| `enabled` | `boolean \| undefined` | no | `true` | Gate the fetch until the host is ready (e.g. the dialog is open). |
| `variant` | `"compact" \| "full" \| undefined` | no | `"full"` | Inline card density. |
| `previewCount` | `number \| undefined` | no | `2` | Precedents shown inline before the "View all" affordance. |
| `result` | `RecallResult \| null \| undefined` | no | - |  |
| `isLoading` | `boolean \| undefined` | no | - |  |
| `error` | `string \| null \| undefined` | no | - |  |
| `onRetry` | `(() => void) \| undefined` | no | - |  |
| `mode` | `DecisionSearchMode \| undefined` | no | `"hybrid"` |  |
| `onModeChange` | `((mode: DecisionSearchMode) => void) \| undefined` | no | - |  |
| `highConfidenceOnly` | `boolean \| undefined` | no | `false` |  |
| `onHighConfidenceOnlyChange` | `((value: boolean) => void) \| undefined` | no | - |  |
| `onViewHypothesis` | `((hypothesisId: string) => void) \| undefined` | no | - | Opens the full institutional-memory detail for another hypothesis (a precedent's own, or an in-flight decision's). Omit to hide the affordance. |

### `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 | - |  |
| `linkage` | `DecisionLinkageProps \| undefined` | no | - | Outcome linkage panel props. Omit to hide the panel entirely. |
| `onExportCsv` | `(() => void) \| undefined` | no | - | Called to export the open hypothesis's details as CSV. Omit to hide the option. |
| `onExportHtml` | `(() => void) \| undefined` | no | - | Called to export the open hypothesis's details as HTML. Omit to hide the option. |
| `isExporting` | `boolean \| undefined` | no | - | When true, the export action shows a spinner and disables the trigger. |
| `chat` | `HypothesisChatProps \| undefined` | no | - | "Ask AI" chat panel props. Omit to hide the panel entirely. |
| `recall` | `Omit<RecallPanelProps, "hypothesisId" \| "enabled"> \| undefined` | no | - | Recall (precedent search) panel props. `hypothesisId` and `enabled` are derived automatically from `group` and `open` - omit them here. Omit the whole prop to hide the panel. |

### `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.5.4

- Add `DecisionLinkagePanel` (and `CandidateList`, `CandidatePickerDialog`, `FeatureVector`, `VerdictForm`, a local `InlineNotice`) under `components/linkage/`, wired into `DecisionLogDetailDialog` via the new `dialog.linkage` prop (`DecisionLinkageProps`). All data-fetching, scan, and verdict-submission logic is the container's responsibility - the panel is fully props-in/events-out.
- Fix `DecisionLogDetailDialog` referencing an undefined `linkableDecisions` and undefined export handlers. Export is now controlled via `onExportCsv` / `onExportHtml` / `isExporting` on `dialog`; the export menu renders only when at least one handler is provided.
- Add `LinkableDecision`, `OutcomeApiError`, `DecisionLinkState`, `CandidateFeaturesLike`, `LinkCandidateLike`, `DecisionLinkLike`, `DecisionLinkScanLike`, `DecisionLinkVerdict`, `DecisionLinkRecordOption`, `DecisionLinkageLinkProps`, and `DecisionLinkageProps` to `InstitutionalMemory01.types.ts`.
- Add `@signalos/dropdown-menu`, `@signalos/textarea`, `@signalos/tooltip`, `@signalos/combobox`, `@signalos/data-primitives`, `@signalos/input` to `registryDependencies` to match imports already used by the block.
- Extract `DecisionLogDetailHeader` from `DecisionLogDetailDialog` (badges, title, export menu, close button) to stay under the 500-line ceiling.
- Add the "Ask AI" chat panel (`HypothesisChat` and its `ChatInput`, `ChatMessageBubble`, `ChatSuggestions`, `ChatThinkingTrace`, `ChatVisualization` subcomponents, plus a local `SectionHeading`) under `components/chat/`, wired into `DecisionLogDetailDialog` via the new `dialog.chat` prop (`HypothesisChatProps`). Suggested questions and their counts are now caller-supplied props (`suggestions`, `emptySuggestionCount`, `followUpSuggestionCount`) instead of fixed content; dark-mode chart rendering is driven by the caller-supplied `isDarkMode` prop instead of reading theme state itself.
- Add `ChatRole`, `ChatVisualizationLike`, `ChatMessage`, `ChatThinkingStep`, `ChatTurnMeta`, `ChatSuggestion`, and `HypothesisChatProps` to `InstitutionalMemory01.types.ts`.
- Add `lucide-react`, `@tanstack/react-table` version pins plus `react-markdown@^9.0.3`, `echarts@^6.1.0`, `echarts-for-react@^3.0.7` to `dependencies`.
- Add the Recall (precedent search) panel (`RecallPanel`, `RecallSection`, `RecallDialog`, `RecallSummaryChip`, `PrecedentCard`, `PrecedentDetail`, `OpenDecisionCard`, `FeatureMeter`, `recall-utils`) under `components/Recall/`, wired into `DecisionLogDetailDialog` via the new `dialog.recall` prop (`RecallPanelProps`, omitting `hypothesisId`/`enabled` which the dialog derives itself). The panel no longer fetches through a Redux hook - `result`, `isLoading`, `error`, `mode`, `highConfidenceOnly` are all props, and `onRetry` / `onModeChange` / `onHighConfidenceOnlyChange` / `onViewHypothesis` are all caller-supplied callbacks that degrade gracefully when omitted.
- Remove `HypothesisDetailDialog`: it depended directly on `next/dynamic`, `@/store`, and a Redux decision-log slice to self-fetch and re-open a hypothesis's detail. Drilling into another hypothesis from a precedent or an in-flight decision is now the plain `onViewHypothesis(hypothesisId)` callback on `dialog.recall` - the container decides how to open that hypothesis's own detail dialog.
- Add `RecallPrecedentFeaturesLike`, `RecallHypothesisSnapshotLike`, `RecallPrecedentLike`, `RecallOpenDecisionLike`, `RecallSummaryLike`, `RecallResult`, and `RecallPanelProps` to `InstitutionalMemory01.types.ts`. `RecallPanelProps.mode` reuses the existing `DecisionSearchMode` type rather than a duplicate.
- Fix a raw-scale token usage in `RecallSummaryChip` (`bg-success-500`/`bg-error-500` → `bg-status-success`/`bg-status-error`).
- Add `@signalos/scroll-area` to `registryDependencies` for `RecallDialog`'s scrollable list.

## 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.
