Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .ai/spec/how/k8s-data-layer.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
|---|---|---|
| `src/models/proposal.ts` | `LightspeedProposalModel`, `LightspeedProposalGVK`, all `*Model`/`*GVK` constants | K8sModel definitions for the Console SDK's watch/patch/create/delete functions |
| `src/models/proposal.ts` | `LightspeedProposal`, `LightspeedProposalApproval`, `*ResultCR` types | TypeScript types for each CRD |
| `src/models/proposal.ts` | `ProposalK8s`, `AnalysisResultK8s`, `ExecutionResultK8s`, `VerificationResultK8s`, `ProposalApprovalK8s` | K8s intersection types (`CRDType & K8sResourceCommon`) for `useK8sWatchResource` generics |
| `src/models/proposal-views.ts` | `ProposalView`, `RemediationOptionView`, `ExecutionView`, `VerificationView` | View-model types — output of the API→view mapping layer |
| `src/hooks/useProposal.ts` | `useProposal`, `mapToProposalView` | Fetches all proposal-related CRs and maps to a single `ProposalView` |
| `src/hooks/useStageApproval.ts` | `useStageApproval` | Encapsulates approval read state + patch write in a single hook |
| `src/utils/approval.ts` | `buildApprovalPatch` | Generates JSON Patch arrays for `AgenticRunApproval` mutations |
| `src/config.ts` | `getApiUrl` | Constructs backend proxy URLs |
Expand Down Expand Up @@ -33,6 +36,8 @@ useK8sWatchResource(AnalysisResultGVK, {namespace, selector: {matchLabels: {agen

This pattern repeats for ExecutionResult, VerificationResult, and EscalationResult. The `results[]` array on each step status contains `{name, outcome}` refs — the name matches the result CR's `metadata.name`.

The `useProposal` hook wraps all five watches (Proposal, AnalysisResult, ExecutionResult, VerificationResult, ProposalApproval) and uses `filterLatest` to select the most recent result CR by `creationTimestamp`. The mapped `ProposalView` is recomputed via `useMemo` whenever any watched resource changes.

### Approval Patch Generation

`buildApprovalPatch` handles three structural cases:
Expand Down Expand Up @@ -60,6 +65,8 @@ Every CRD has a paired `K8sModel` (used by Console SDK functions) and a `GVK` ob

CRD types are hand-written, not generated. A TODO exists to auto-generate from OpenAPI. The types closely mirror the CRD status structure — changes in the operator's CRD require manual synchronization here.

K8s intersection types (e.g., `ProposalK8s = LightspeedProposal & K8sResourceCommon`) are defined at the bottom of `proposal.ts` for use with `useK8sWatchResource` generics. A separate view-model layer in `proposal-views.ts` defines UI-optimized types (`ProposalView`, `RemediationOptionView`, etc.) with `*View` suffix. The `useProposal` hook in `src/hooks/useProposal.ts` contains pure mapping functions (`mapRootCause`, `mapOption`, `mapExecution`, `mapVerification`, `mapTimeline`) that transform API types into view types. Phase derivation is centralized in `derivePhaseFromConditions` (defined in `proposal.ts`, used by both list and detail pages).

### Approval State Machine

The `useStageApproval` hook combines:
Expand Down
26 changes: 18 additions & 8 deletions .ai/spec/how/project-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,22 @@
| `src/utils/approval.ts` | `findStage`, `getStageStatus`, `stageNeedsApproval`, `buildApprovalPatch` | Pure functions for approval logic |
| `src/hooks/useStageApproval.ts` | `useStageApproval` | React hook wrapping approval state and K8s patch operations |
| `src/utils/markdown.ts` | — | Markdown rendering utilities |
| `src/components/proposals/ProposalListPage.tsx` | `ProposalListPage` | Run list with virtualized table and phase filters |
| `src/components/proposals/ProposalDetailPage.tsx` | `ProposalDetailPage`, `OverviewTab`, `ProposalTab`, `ResultTab`, `VerificationTab`, `EscalationTab` | Multi-tab run detail with approval flows |
| `src/components/proposals/SandboxLogViewer.tsx` | `SandboxLogViewer` | Real-time pod log streaming with reconnection |
| `src/components/proposals/EscalateModal.tsx` | `EscalateModal` | Escalation confirmation modal |
| `src/components/proposals/MarkdownText.tsx` | `MarkdownText` | Sanitized markdown-to-HTML rendering |
| `src/components/proposals/PhaseIcon.tsx` | `PhaseIcon` | Phase status icon with failure indicators |
| `src/components/proposals/DynamicComponent.tsx` | `DynamicComponent` | Component registry dispatch for adapter components |
| `src/components/proposals/ProposalListPage.tsx` | `ProposalListPage` | Proposal list with virtualized table and phase filters |
| `src/components/proposals/ProposalDetailPage.tsx` | `ProposalDetailsPage` | Section-based proposal detail page, delegates to `detail/` subcomponents |
| `src/components/proposals/detail/AnalysisSummary.tsx` | `AnalysisSummary` | Root cause display, analysis loading/streaming state |
| `src/components/proposals/detail/RemediationOptionCard.tsx` | `RemediationOptionCard` | Expandable remediation option card |
| `src/components/proposals/detail/ExecutionSummary.tsx` | `ExecutionSummary` | Post-execution actions and outcome display |
| `src/components/proposals/detail/VerificationSummary.tsx` | `VerificationSummary` | Verification checks and summary |
| `src/components/proposals/detail/ProposalPhaseLabel.tsx` | `ProposalPhaseLabel` | Phase label with status color |
| `src/components/proposals/detail/ProposalTimeline.tsx` | `ProposalTimeline` | Chronological event timeline |
| `src/components/proposals/detail/StageInProgress.tsx` | `StageInProgress` | In-progress stage card with embedded log viewer |
| `src/components/proposals/detail/SandboxLogViewer.tsx` | `SandboxLogViewer` | Expandable log viewer with streaming and search |
| `src/components/StatusGuard.tsx` | `StatusGuard` | Loading/error/empty gate using PatternFly `ErrorState`; replaces internal console `StatusBox` |
| `src/models/proposal-views.ts` | `ProposalView`, `RemediationOptionView`, `ExecutionView`, `VerificationView`, `SandboxView`, `TimelineEvent`, `TERMINAL_PHASES` | View-model types for the detail page (output of `useProposal` mapping layer) |
| `src/constants.ts` | `PROPOSAL_NAMESPACE`, `PROPOSAL_LABEL_SOURCE`, `RESULT_LABEL_PROPOSAL` | Shared constants for K8s label keys and namespace |
| `src/hooks/useProposal.ts` | `useProposal`, `mapRootCause`, `mapOption`, `mapExecution`, `mapVerification`, `mapTimeline`, `filterLatest` | Fetches proposal + result CRs, maps API types → view types |
| `src/hooks/useExecutionLogActions.ts` | `useExecutionLogActions` | Parses execution actions from sandbox pod logs |
| `src/hooks/useSandboxLogStream.ts` | `useSandboxLogStream` | Streams audit lines from sandbox pod logs |
| `src/components/proposals/dynamic/` | `ResourceDiff`, `Visualization`, `DataTable`, `ActionPicker`, `EvidenceTable`, `StatusTimeline`, `CmoComponents` | Individual dynamic component renderers |
| `src/components/configuration/ConfigurationPage.tsx` | `ConfigurationPage` | Configuration page with tabbed layout |
| `src/components/configuration/ApprovalPolicyTab.tsx` | `ApprovalPolicyTab` | Approval policy CRUD |
Expand All @@ -42,6 +51,7 @@ The plugin has no traditional `main` entry point. Webpack's `ConsoleRemotePlugin

- Components: PascalCase `.tsx` files, one primary component per file, default export.
- CSS: co-located `.css` files alongside components. All classes prefixed `ols-plugin__`.
- Models: singular `proposal.ts` contains all CRD types (not split by CRD).
- Models: `proposal.ts` contains all CRD types and K8s intersection types. `proposal-views.ts` contains view-model types (`*View` suffix) for the detail page.
- Hooks: `use` prefix, one hook per file in `src/hooks/`.
- Detail subcomponents: each section of the detail page is a separate component in `src/components/proposals/detail/`, imported by `ProposalDetailPage.tsx`.
- Dynamic components: each renderer in `src/components/proposals/dynamic/`, re-exported via `index.tsx`.
11 changes: 5 additions & 6 deletions .ai/spec/what/run-lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,12 @@ The core domain of the plugin: displaying and managing runs through a multi-stag
8. The list MUST support filtering by phase and text search.
9. Each row MUST show: name (linked to detail), phase label, request preview (truncated to 80 chars), namespace, and age.

### Run Detail — Tabs
### Run Detail — Layout

10. The detail page MUST show tabs: Overview, Proposal, Execution, Verification, and conditionally Escalation.
11. The Escalation tab MUST only appear when the run has an `Escalated` condition.
12. For CMO (cluster-monitoring-operator) sourced runs, the Overview tab is hidden and the default tab is Proposal.
13. A blue dot indicator MUST appear on the tab corresponding to the currently active phase when the user is viewing a different tab.
14. Tabs that need approval MUST show a "Needs approval" badge.
10. The detail page MUST gate its content behind a loading/error guard (`StatusGuard`): show a spinner while loading, an error state on failure (403 → restricted access, 404 → not found, other → error message with detail), and the page content when data is ready.
11. The detail page uses a single-page section layout (not tabs). Sections are rendered conditionally based on the current phase: Analysis summary, Remediation options, Execution summary, Verification summary, and Timeline.
12. During in-progress stages (Analyzing, Executing, Verifying), the page MUST show a `StageInProgress` card with embedded live log streaming from the sandbox pod.
13. The page MUST be wrapped in `AgenticLayout` to display the system-suspended banner when the agentic config has `suspended: true`.

### Approval Flow

Expand Down
Loading