From 25579e52a3242a4282080148601408c5cc9df033 Mon Sep 17 00:00:00 2001 From: xavier Date: Fri, 29 May 2026 17:15:53 -0400 Subject: [PATCH] OLS-2882 Align spec structure and fix health issues Co-Authored-By: Claude Opus 4.6 (1M context) --- .ai/spec/README.md | 74 ++++++++++++--- .ai/spec/health-report.md | 35 +++++++ .ai/spec/how/README.md | 23 ----- .ai/spec/how/project-structure.md | 14 ++- .ai/spec/what/README.md | 26 ------ .ai/spec/what/attachments.md | 1 - .ai/spec/what/tools.md | 1 - AGENTS.md | 4 + ARCHITECTURE.md | 149 ++++++++++++++++++++++++++++++ 9 files changed, 262 insertions(+), 65 deletions(-) create mode 100644 .ai/spec/health-report.md delete mode 100644 .ai/spec/how/README.md delete mode 100644 .ai/spec/what/README.md create mode 100644 ARCHITECTURE.md diff --git a/.ai/spec/README.md b/.ai/spec/README.md index 8e0320bd..16276c12 100644 --- a/.ai/spec/README.md +++ b/.ai/spec/README.md @@ -1,9 +1,13 @@ -# OpenShift LightSpeed Console Plugin -- Specifications +# OpenShift LightSpeed Console Plugin — Specifications -These specs define the requirements, behaviors, and architecture for the OLS console plugin (lightspeed-console). They are organized into two layers: +The OLS console plugin is an OpenShift Console dynamic plugin that provides an AI chat assistant UI. These specs define what the plugin must do (behavioral rules) and how the current implementation is structured (codebase navigation). -- **[`what/`](what/README.md)** -- Behavioral rules: WHAT the plugin must do and WHY. Technology-neutral, testable assertions. Use these to understand requirements, fix bugs, or rebuild components. -- **[`how/`](how/README.md)** -- Architecture specs: HOW the current implementation is structured. Module boundaries, data flow, design patterns. Use these to navigate, modify, and extend the codebase. +## Structure + +| Layer | Path | Purpose | +|---|---|---| +| **what/** | `.ai/spec/what/` | Behavioral rules. What the system must do. Implementation-agnostic. | +| **how/** | `.ai/spec/how/` | Codebase navigation. How the code is organized. Implementation-specific. | ## Scope @@ -11,12 +15,12 @@ These specs cover the **lightspeed-console** TypeScript/React dynamic plugin onl ## Audience -AI agents (Claude). Specs optimize for precision, unambiguous rules, and machine-parseable structure. +AI agents. Content is optimized for precision and machine consumption. ## Quick Start -| I want to... | Read | -|--------------|------| +| Task | Start here | +|---|---| | Understand what this plugin does | `what/system-overview.md` | | Fix a bug in chat or streaming | `what/chat.md` + `how/streaming.md` | | Add a new attachment type | `what/attachments.md` + `how/components.md` | @@ -26,9 +30,57 @@ AI agents (Claude). Specs optimize for precision, unambiguous rules, and machine | Understand state management | `how/state-management.md` | | See what's planned | Look for `[PLANNED: OLS-XXXX]` in `what/` specs | +## What/ — Behavioral Specs + +These specs define WHAT the plugin must do — testable behavioral rules, configuration surface, constraints, and planned changes. They are technology-neutral where possible and survive a complete rewrite in a different framework. + +| Spec | Description | +|------|-------------| +| [system-overview.md](what/system-overview.md) | Plugin identity, scope, system boundaries, deployment model, relationship to OLS service | +| [chat.md](what/chat.md) | Chat lifecycle, query submission, streaming responses, query modes, conversation management, first-time UX | +| [attachments.md](what/attachments.md) | All attachment types (YAML, filtered YAML, events, logs, alerts, file upload, ManagedCluster), context detection, editing | +| [tools.md](what/tools.md) | Tool call display, human-in-the-loop approval workflow, MCP App interactive UI, OLS tool UI extensions | +| [feedback.md](what/feedback.md) | User feedback (thumbs up/down, free-text), feedback enabled/disabled, privacy notice | +| [auth.md](what/auth.md) | Authorization check flow, auth status handling, bearer token forwarding | +| [plugin-api.md](what/plugin-api.md) | Console extension points, useOpenOLS public API, ols.tool-ui extension type, user settings | + +**How to use what/ specs:** +- **Fixing a bug**: Read the relevant spec to understand correct behavior, then compare against the code. +- **Adding a feature**: Check if the spec covers the requirement. Update the spec before implementing. +- **Refactoring**: Use the specs as acceptance criteria. The implementation can change freely as long as it meets the behavioral rules. + +## How/ — Architecture Specs + +These specs describe HOW the plugin is structured — module boundaries, data flow, design patterns, key abstractions, and implementation decisions. They are grounded in the current TypeScript/React codebase and should be updated when the code changes. + +| Spec | Description | +|------|-------------| +| [project-structure.md](how/project-structure.md) | Directory layout, module responsibilities, build system, dependencies, dev setup, testing | +| [state-management.md](how/state-management.md) | Redux store shape, Immutable.js usage, actions, reducer, selectors | +| [streaming.md](how/streaming.md) | SSE stream processing, event types, buffering, throttled dispatch, abort handling | +| [components.md](how/components.md) | Component tree, Popover/GeneralPage/Prompt hierarchy, PatternFly Chatbot integration | + +**When to read how/ specs:** +- **Navigating the codebase**: Start with `project-structure.md` to understand where things live. +- **Modifying a subsystem**: Read the relevant spec to understand the current architecture before making changes. +- **Debugging streaming issues**: The `streaming.md` spec traces the exact event processing path. + +## Cross-Reference + +| what/ | how/ | +|---|---| +| `what/system-overview.md` | `how/project-structure.md` | +| `what/chat.md` | `how/streaming.md`, `how/components.md` | +| `what/attachments.md` | `how/components.md` | +| `what/tools.md` | `how/components.md` | +| `what/feedback.md` | `how/state-management.md` | +| `what/auth.md` | `how/project-structure.md` | +| `what/plugin-api.md` | `how/project-structure.md`, `how/state-management.md` | + ## Conventions -- `[PLANNED: OLS-XXXX]` markers in `what/` specs indicate existing rules about to change due to open Jira work -- "Planned Changes" sections list new capabilities not yet in code -- Internal constants are stated as behavioral rules without numeric values; `how/` specs may include specific values -- User-configurable values are referenced by their user settings key path +- **Rule numbering:** behavioral rules are numbered sequentially within each what/ file. +- **Planned changes:** unimplemented behavior is marked with `[PLANNED]` or `[PLANNED: OLS-XXXX]` inline next to the rule it affects. +- **Constraints:** component-specific and cross-cutting constraints go in the relevant what/ file's Constraints section, co-located with behavioral rules. Development conventions go in CLAUDE.md. +- **Authority:** what/ specs are authoritative for behavior. how/ specs are authoritative for implementation. When they conflict, what/ wins. +- **When to create a new file vs. extend an existing one:** if the new concern has its own lifecycle, configuration surface, and can be understood independently, it gets its own file. If it's a capability added to an existing component, it goes in that component's file. diff --git a/.ai/spec/health-report.md b/.ai/spec/health-report.md new file mode 100644 index 00000000..fff0c1b9 --- /dev/null +++ b/.ai/spec/health-report.md @@ -0,0 +1,35 @@ +# Spec health report + +Last evaluated: 2026-05-29 +Trigger: post-milestone (spec-first alignment) +Layout: software (.ai/spec/) + +## Stale + +- **`how/project-structure.md` references two deleted components**: `src/components/CloseButton.tsx` and `src/components/Modal.tsx` are listed in the Module Map but do not exist in the codebase. These were likely removed or inlined into other components. +- **Planned Changes contain completed tickets**: `what/attachments.md` lists OLS-1401 as "(completed)" and `what/tools.md` lists OLS-2683 as "(completed)". Completed tickets should be removed from Planned Changes tables — the implemented behavior is already captured in the behavioral rules above. + +## Missing + +- **`src/pageContext.ts` not in spec**: This module contains `resolveModelKey()` which handles URL resource key resolution (direct model keys, plural-based keys, group~version~kind references). It supports attachment context detection and should be documented in `how/project-structure.md` Module Map. +- **`src/validation.ts` not in spec**: This module contains `alertingRuleID()` (murmur3 hash generation matching the monitoring-console-plugin's rule ID format) and `isValidAlertName()`. It supports alert attachment behavior and should be in `how/project-structure.md` Module Map. +- **CSS files not in spec**: Three CSS files exist in `src/components/` (`general-page.css`, `mcp-app.css`, `popover.css`) but are not mentioned in `how/project-structure.md` or `how/components.md`. +- **Unit test coverage gap in spec**: `unit-tests/` includes tests for `pageContext` and `validation` — modules not documented in the spec. The test directory description in `how/project-structure.md` mentions "Tests for: redux-reducers, error handling, attachments" but doesn't mention pageContext or validation tests. + +## Structural concerns + +- None. The what/how separation is clean — behavioral rules are in what/, implementation details are in how/. No duplicated information was found across files. + +## Findability issues + +- None. The Cross-Reference table in README.md makes it straightforward to navigate between behavioral specs and their implementation counterparts. + +## No issues + +- All 9 hooks in `src/hooks/` match the spec's Module Map. +- All 23 existing components in `src/components/` (excluding the 2 deleted ones) match the spec. +- All 3 assets in `src/assets/` match the spec. +- The 5 console extensions in `console-extensions.json` match the spec exactly. +- The 27 Redux actions and 27 reducer cases match the spec's claim. +- The Redux state shape in `how/state-management.md` matches the reducer implementation. +- The streaming event types in `how/streaming.md` match the behavioral rules in `what/chat.md`. diff --git a/.ai/spec/how/README.md b/.ai/spec/how/README.md deleted file mode 100644 index b5989c88..00000000 --- a/.ai/spec/how/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Architecture Specifications (how/) - -These specs describe HOW the OLS console plugin is structured -- module boundaries, data flow, design patterns, key abstractions, and implementation decisions. They are grounded in the current TypeScript/React codebase and should be updated when the code changes. - -## Spec Index - -| Spec | Description | -|------|-------------| -| [project-structure.md](project-structure.md) | Directory layout, module responsibilities, build system, dependencies, dev setup, testing | -| [state-management.md](state-management.md) | Redux store shape, Immutable.js usage, actions, reducer, selectors | -| [streaming.md](streaming.md) | SSE stream processing, event types, buffering, throttled dispatch, abort handling | -| [components.md](components.md) | Component tree, Popover/GeneralPage/Prompt hierarchy, PatternFly Chatbot integration | - -## When to Read These - -- **Navigating the codebase**: Start with `project-structure.md` to understand where things live. -- **Modifying a subsystem**: Read the relevant `how/` spec to understand the current architecture before making changes. -- **Adding a new attachment type or tool UI**: The `components.md` spec includes extension points. -- **Debugging streaming issues**: The `streaming.md` spec traces the exact event processing path. - -## Relationship to what/ Specs - -The [`what/` specs](../what/README.md) define behavioral contracts (technology-neutral). These `how/` specs describe the implementation that fulfills those contracts. When the two diverge, the `what/` spec is the source of truth for correct behavior, and the `how/` spec should be updated to reflect the current code. diff --git a/.ai/spec/how/project-structure.md b/.ai/spec/how/project-structure.md index b42ece20..2d44df56 100644 --- a/.ai/spec/how/project-structure.md +++ b/.ai/spec/how/project-structure.md @@ -18,6 +18,8 @@ and communicates with the OLS backend service via the console's plugin proxy. | `src/error.ts` | `ErrorType` and `FetchError` types. `getFetchErrorMessage()` extracts structured error messages from fetch responses, handling both string and object `detail` fields. | | `src/flags.ts` | `FLAG_LIGHTSPEED_PLUGIN` constant and `enableLightspeedPluginFlag()` handler for the `console.flag` extension. | | `src/clipboard.ts` | `copyToClipboard(value)` utility wrapping `navigator.clipboard.writeText()`. | +| `src/pageContext.ts` | `resolveModelKey()` resolves URL resource keys to K8s model keys. Handles direct model keys (e.g., `Pod`), plural-based keys (e.g., `pods`), and group~version~kind references (e.g., `core~v1~Pod`). | +| `src/validation.ts` | `alertingRuleID()` generates murmur3 hash matching the monitoring-console-plugin's alerting rule ID format. `isValidAlertName()` validates alert name strings. | ### `src/hooks/` -- Custom React hooks @@ -51,7 +53,6 @@ and communicates with the OLS backend service via the console's plugin proxy. | `src/components/AttachEventsModal.tsx` | Modal for selecting Kubernetes events to attach. | | `src/components/AttachLogModal.tsx` | Modal for selecting pod logs. Container selection, line count slider, live preview. | | `src/components/ErrorBoundary.tsx` | React error boundary. Catches component crashes and renders fallback. | -| `src/components/Modal.tsx` | Reusable modal wrapper component. | | `src/components/ResourceIcon.tsx` | Renders Kubernetes resource kind icons. | | `src/components/CopyAction.tsx` | Copy-to-clipboard button with visual confirmation. | | `src/components/ImportAction.tsx` | "Import YAML" action button. Opens confirmation modal, then navigates to console's YAML import page with content. | @@ -59,12 +60,19 @@ and communicates with the OLS backend service via the console's plugin proxy. | `src/components/ReadinessAlert.tsx` | Alert shown when OLS service is not ready. | | `src/components/WelcomeNotice.tsx` | Welcome message for first-time users. | | `src/components/ConfirmationModal.tsx` | Generic confirmation dialog. | -| `src/components/CloseButton.tsx` | Close icon button. | | `src/components/NullContextProvider.tsx` | No-op React context provider returning `null`. Used as the component for the `console.context-provider` extension. | | `src/components/OverviewDetail.tsx` | Dashboard detail item showing plugin version. | ### `src/assets/` -- Static assets +| Path | Purpose | +|---|---| +| `src/components/general-page.css` | Styles for the GeneralPage chat interface | +| `src/components/mcp-app.css` | Styles for MCP App card and iframe container | +| `src/components/popover.css` | Styles for the Popover modal and floating button | + +### `src/assets/` -- Static assets + | Path | Purpose | |---|---| | `src/assets/logo.svg` | OLS logo for light theme | @@ -91,7 +99,7 @@ and communicates with the OLS backend service via the console's plugin proxy. | `tests/` | Cypress e2e test specs | | `cypress/` | Cypress support files and fixtures | | `cypress.config.ts` | Cypress configuration | -| `unit-tests/` | Unit tests using Node's built-in test runner. Tests for: redux-reducers, error handling, attachments | +| `unit-tests/` | Unit tests using Node's built-in test runner. Tests for: redux-reducers, error handling, attachments, pageContext (model key resolution), validation (alert rule ID hashing) | ## Data Flow diff --git a/.ai/spec/what/README.md b/.ai/spec/what/README.md deleted file mode 100644 index bd7441bd..00000000 --- a/.ai/spec/what/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Behavioral Specifications (what/) - -These specs define WHAT the OLS console plugin must do -- testable behavioral rules, configuration surface, constraints, and planned changes. They are technology-neutral where possible and survive a complete rewrite in a different framework. - -## Spec Index - -| Spec | Description | -|------|-------------| -| [system-overview.md](system-overview.md) | Plugin identity, scope, system boundaries, deployment model, relationship to OLS service | -| [chat.md](chat.md) | Chat lifecycle, query submission, streaming responses, query modes, conversation management, first-time UX | -| [attachments.md](attachments.md) | All attachment types (YAML, filtered YAML, events, logs, alerts, file upload, ManagedCluster), context detection, editing | -| [tools.md](tools.md) | Tool call display, human-in-the-loop approval workflow, MCP App interactive UI, OLS tool UI extensions | -| [feedback.md](feedback.md) | User feedback (thumbs up/down, free-text), feedback enabled/disabled, privacy notice | -| [auth.md](auth.md) | Authorization check flow, auth status handling, bearer token forwarding | -| [plugin-api.md](plugin-api.md) | Console extension points, useOpenOLS public API, ols.tool-ui extension type, user settings | - -## How to Use These Specs - -- **Fixing a bug**: Read the relevant spec to understand correct behavior, then compare against the code. -- **Adding a feature**: Check if the spec covers the requirement. Update the spec before implementing. -- **Refactoring**: Use the specs as acceptance criteria. The implementation can change freely as long as it meets the behavioral rules. -- **Understanding planned work**: Look for `[PLANNED: OLS-XXXX]` markers inline and "Planned Changes" sections. - -## Relationship to how/ Specs - -These `what/` specs define the behavioral contract. The [`how/` specs](../how/README.md) describe the current implementation architecture. Read `what/` to understand requirements, read `how/` to understand the codebase structure. diff --git a/.ai/spec/what/attachments.md b/.ai/spec/what/attachments.md index 11d1d1f9..9200a3fc 100644 --- a/.ai/spec/what/attachments.md +++ b/.ai/spec/what/attachments.md @@ -144,7 +144,6 @@ sending. | Jira Key | Summary | |---|---| -| OLS-1401 | Upload local YAML files (completed) | | OLS-1896 | ACM: Attach ApplicationSet objects from Applications page | | OLS-2065 | ACM: Attach policy violations | | OLS-2116 | ACM: Attach cluster info in ACM-enabled environments | diff --git a/.ai/spec/what/tools.md b/.ai/spec/what/tools.md index b0890c7b..ebffd517 100644 --- a/.ai/spec/what/tools.md +++ b/.ai/spec/what/tools.md @@ -152,7 +152,6 @@ interactive MCP App UIs and OLS-native tool visualizations. | Jira Key | Summary | |---|---| -| OLS-2683 | MVP for HITL approve/deny (completed) | | OLS-2722 | OLS Tool UI extensibility from external plugins | | OLS-2598 | MCP Apps support in OLS console | | OLS-1556 | Display info about tools called while generating OLS response | diff --git a/AGENTS.md b/AGENTS.md index 2a356af2..80f70193 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,3 +1,7 @@ +## Specs + +All specifications live in `.ai/spec/`. Start with `.ai/spec/README.md` for project overview, reading order, and structure guide. + ## AI Agents Guide Basic guardrails and quick-start for AI coding agents contributing to this diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 00000000..e98e87fe --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,149 @@ +# Architecture + +The OpenShift LightSpeed console plugin is a dynamic plugin for the OpenShift web console that adds an AI chat assistant. It runs inside the console as a Webpack Module Federation remote, communicating with the OLS backend service (lightspeed-service) through the console's built-in plugin proxy. + +## System Context + +```mermaid +graph LR + User([User]) --> Console[OpenShift Web Console] + Console --> Plugin[LightSpeed Console Plugin] + Plugin -->|plugin proxy| OLS[OLS Backend Service] + OLS --> LLM[LLM Provider] + OLS --> RAG[RAG Content] + OLS --> MCP[MCP Servers] + Plugin -->|K8s API proxy| K8s[Kubernetes API] +``` + +The plugin is a pure UI client — it has no local AI processing, no persistent storage, and no direct LLM communication. All intelligence comes from the OLS backend service. + +## Component Architecture + +```mermaid +graph TD + CE[console-extensions.json] -->|registers| Flag[Feature Flag] + CE -->|registers| CP[Context Provider] + CE -->|registers| Reducer[Redux Reducer] + CE -->|registers| Action[Action Provider] + CE -->|registers| Dashboard[Dashboard Detail] + + CP -->|launches once| Popover + Action -->|exposes| useOpenOLS + + Popover --> GP[GeneralPage] + GP --> Header[ChatbotHeader] + GP --> Content[ChatbotContent] + GP --> Footer[ChatbotFooter] + + Content --> Messages[ChatHistoryEntry list] + Messages --> UserMsg[User Message] + Messages --> AIMsg[AI Message] + + AIMsg --> Tools[ResponseTools] + AIMsg --> Approval[ToolApproval] + AIMsg --> Feedback[UserFeedbackForm] + + Tools --> MCPApp[MCPApp iframe] + Tools --> OlsToolUI[OLS Tool UIs] + Tools --> Labels[Tool Labels] + + Footer --> Prompt[Prompt + MessageBar] + Prompt --> AttachMenu[Attachment Menu] + Prompt --> StreamProcessor[SSE Stream Reader] +``` + +The plugin registers five console extensions at load time. The context provider launches the Popover as a console modal exactly once. From there, GeneralPage renders the chat interface with PatternFly Chatbot components. + +## Data Flow + +### Query Lifecycle + +```mermaid +sequenceDiagram + participant U as User + participant P as Prompt.tsx + participant R as Redux Store + participant API as OLS Service (via proxy) + + U->>P: Type prompt + attach context + P->>R: Push user entry + AI placeholder + P->>API: POST /v1/streaming_query (SSE) + + loop SSE Events + API-->>P: start (conversation_id) + P->>R: setConversationID + API-->>P: token (text chunk) + P->>R: chatHistoryUpdateByID (throttled) + API-->>P: tool_call / approval_required / tool_result + P->>R: chatHistoryUpdateTool + API-->>P: end (references, truncated) + P->>R: chatHistoryUpdateByID (final) + end + + U->>P: Thumbs up/down + P->>API: POST /v1/feedback +``` + +Responses are streamed as Server-Sent Events. Token updates are throttled to prevent excessive re-renders. The stream reader buffers incomplete lines across TCP chunks. + +### Tool Approval (Human-in-the-Loop) + +When the OLS service needs user approval for a tool call, it sends an `approval_required` SSE event. The plugin renders an approval card with Approve/Reject buttons. The decision is POSTed back to the service, which then continues or halts the tool execution. + +### MCP App Interactive UI + +Some tool results include a UI resource URI pointing to an HTML application hosted by an MCP server. The plugin loads this HTML into a sandboxed iframe (`allow-scripts` only) and communicates with it via bidirectional JSON-RPC 2.0 over `postMessage`. + +## State Management + +All plugin state lives in a single Redux reducer registered under `state.plugins.ols`. State values use Immutable.js (`ImmutableMap` and `ImmutableList`), accessed via `.get()` and `.getIn()` rather than property access. + +Key state slices: +- **UI state**: popover open/close, display mode, query mode, auto-submit flag +- **Chat content**: ordered history of user and AI entries, current prompt text, conversation ID +- **Attachments**: map of attached resources keyed by composite ID +- **Tool interaction**: currently open tool detail modal + +State is in-memory only — nothing persists across page refreshes. + +## API Surface + +All OLS API calls go through the console's plugin proxy at `/api/proxy/plugin/lightspeed-console-plugin/ols/`. + +| Method | Path | Purpose | +|--------|------|---------| +| POST | `/authorized` | Authorization check | +| POST | `/v1/streaming_query` | Submit query, receive SSE stream | +| GET | `/v1/feedback/status` | Check if feedback is enabled | +| POST | `/v1/feedback` | Submit user feedback | +| POST | `/v1/tool-approvals/decision` | Approve/deny tool execution | +| POST | `/v1/mcp-apps/tools/call` | Direct MCP tool call (from iframe) | +| POST | `/v1/mcp-apps/resources` | Load MCP App UI resource (HTML) | + +## Extension Points + +Other console plugins can interact with this plugin through: + +1. **Feature flag** — `LIGHTSPEED_PLUGIN` indicates the plugin is loaded +2. **Action provider** — `useOpenOLS` hook lets other plugins open the chat with a prompt, attachments, and optional auto-submit +3. **Tool UI extensions** — `ols.tool-ui` extension type lets other plugins register custom visualization components for specific tool results + +## Technology Stack + +- **Framework**: React 18 + TypeScript (ES2020 target) +- **Build**: Webpack 5 with Module Federation (`ConsoleRemotePlugin`) +- **UI library**: PatternFly 6 + PatternFly AI Chatbot +- **State**: Redux + Immutable.js +- **Console SDK**: `@openshift-console/dynamic-plugin-sdk` +- **Testing**: Cypress (e2e), Node built-in test runner (unit) +- **Linting**: ESLint + Prettier + Stylelint + +## Key Architectural Decisions + +**Streaming in Prompt.tsx** — All SSE stream processing lives in a single component (`Prompt.tsx`) inside the `onSubmit` callback closure. This co-locates input handling and stream processing, making `Prompt.tsx` the largest component but keeping streaming state per-request and automatically cleaned up. + +**Immutable.js for Redux state** — State uses `ImmutableMap`, providing structural sharing for efficient updates but no compile-time key safety. Access requires `.get()` / `.getIn()` ceremony throughout the codebase. + +**Plugin proxy for all API calls** — The plugin never connects directly to the OLS service. The console's proxy handles authentication, TLS, and routing. In development, `start-console.sh` adds an additional proxy from the console container to `localhost:8080`. + +**Auto-submit via DOM click** — Programmatic submission clicks the MessageBar's send button rather than calling `onSubmit` directly, because the PatternFly MessageBar manages internal state that would otherwise get out of sync.