From 5382072118edd71bb54df4e6c36c670ea2759053 Mon Sep 17 00:00:00 2001 From: xavier Date: Mon, 31 Aug 2026 17:23:31 -0400 Subject: [PATCH] OLS-0000 Sync .ai/spec with current code Spec drift fix from spec-first health + init (alignment): console-plugin removal shipped; drop deleted controller/sandbox; TokenUsage shipped; fix ClientFactory contradiction & moved symbols Co-Authored-By: Claude Opus 4.8 --- .ai/spec/health-report.md | 54 +++++++++++++++++------------- .ai/spec/how/project-structure.md | 16 ++++----- .ai/spec/how/reconciler.md | 20 ++++------- .ai/spec/what/crd-api.md | 12 +++---- .ai/spec/what/sandbox-execution.md | 4 +-- .ai/spec/what/system-overview.md | 9 +++-- .ai/spec/what/templog.md | 3 +- 7 files changed, 58 insertions(+), 60 deletions(-) diff --git a/.ai/spec/health-report.md b/.ai/spec/health-report.md index 7901889c..576840df 100644 --- a/.ai/spec/health-report.md +++ b/.ai/spec/health-report.md @@ -1,39 +1,47 @@ # Spec health report -Last evaluated: 2026-07-27 -Trigger: post OLS-3685/OLS-3686 implementation (SandboxManager unification, config cache) +Last evaluated: 2026-08-31 +Trigger: post-milestone (console removal OLS-3350, TokenUsage OLS-3993) — staleness + accuracy check Layout: software (.ai/spec/) ## Stale -1. **what/crd-api.md rule 18** — States "Agent — `status.conditions`: Observed readiness; `Ready` condition documents whether referenced provider resources are accessible (see operator reconcile behavior)." No Agent reconciler exists in the codebase; the operator only reconciles `AgenticRun` CRs. Rule 18 should be marked `[PLANNED]` or reworded to clarify this is aspirational rather than implemented behavior. +1. **Console plugin removal shipped, still marked `[PLANNED: OLS-3236]`.** `controller/console/` is deleted (commit f88e0e1 "OLS-3350: Remove console plugin deployment from agentic-operator"). `cmd/main.go` no longer parses `--agentic-console-image`, registers no `EnsureAgenticConsole` RunnableFunc, and its scheme registers only `clientgoscheme` + `agenticv1alpha1` (no `consolev1` / `openshiftv1`). Affected: + - `what/system-overview.md` rules 5a, 6, 12 (marked `[PLANNED: OLS-3236]` — now DONE), Constraints line "requires OpenShift APIs for console plugin deployment" (no longer true), Planned Changes OLS-3236 row. + - `how/project-structure.md` module map row `controller/console/`; entry-point bullets listing `--agentic-console-image`, "Registers console plugin", "Registers `EnsureAgenticConsole` as a `RunnableFunc`". + - `how/reconciler.md` entire "Module map: `controller/console/`" section; scheme note claiming `consolev1` + `openshiftv1` registration. + +2. **`controller/sandbox/` deleted, still in module map.** `how/project-structure.md` lists `controller/sandbox/` ("Legacy bootstrap helpers"); the directory no longer exists (SA bootstrap is inline in `cmd/main.go`). + +3. **TokenUsage shipped, still marked `[PLANNED: OLS-3661]`.** `TokenUsage` (both `inputTokens`/`outputTokens` `+required`, `MinProperties=1`) exists in `api/v1alpha1` on all four Result types and `AgenticRunStatus`; aggregation is implemented in `controller/agenticrun/results.go` (shipped as OLS-3993, building on the OLS-3661 spec). All `[PLANNED: OLS-3661]` markers are stale: + - `what/crd-api.md` rules 6c, 6d, 6e, 31–34, config-surface lines, Planned Changes OLS-3661 row. + - `what/sandbox-execution.md` rule 43.1 and Planned Changes OLS-3661 row. + +4. **`how/reconciler.md` internal contradiction — `SandboxAgentCaller` fields.** DI wiring line lists `{Sandbox, K8sClient, ClientFactory, Namespace, Audit}`, but the actual struct is `{Sandbox, K8sClient, Namespace, Audit}` and the same doc later states `ClientFactory` was removed under OLS-3066. `ClientFactory` no longer exists anywhere in the code. + +5. **Moved function — `buildInputConfigMap`.** `how/reconciler.md` attributes `buildInputConfigMap` to `sandbox_manager.go`; it now lives in `controller/agenticrun/input_configmap.go`. + +6. **Stale cross-reference — `pkg/telemetry/`.** `what/templog.md` cross-references `pkg/telemetry/` for the provider implementation; telemetry/OTLP code lives in `pkg/configuration/otel_provider.go` and audit code in `controller/agenticrun/audit.go`. No `pkg/telemetry/` package exists. ## Missing -1. **Console plugin behavioral rules** — `controller/console/` deploys a console plugin (Deployment, Service, ConfigMap, ConsolePlugin CR, Console activation), but no what/ file defines behavioral rules for this component. It is only documented in how/reconciler.md as implementation detail. Consider adding a `what/console-plugin.md` if the console deployment has rules worth specifying (idempotency, image absence handling, activation semantics). +1. **`how/reconciler.md` module map omits shipped files.** `controller/agenticrun/audit.go` (AuditLogger, ProductionAuditLogger, LogEmitter), `approval_webhook.go` (AgenticRunApprovalMutator — the audit MutatingAdmissionWebhook of `audit-logging.md` rules 17–21), and `input_configmap.go` (buildInputConfigMap, buildResultTemplate) have no module-map entries, despite their behavior being specified in `what/audit-logging.md` and `what/sandbox-execution.md`. -2. **`pkg/configuration/` spec** — The new configuration cache package (`Config`, `Cache`, `OnConfigMapChange`) has no dedicated spec file. Covered in `docs/inter-operator-handoff-design.md` but not in `.ai/spec/`. Consider adding `how/configuration.md` if the package grows. +2. **`how/project-structure.md` omits `controller/agenticolsconfig/`** (the AgenticOLSConfig status reconciler), which is documented in `how/reconciler.md`. Also omits `cli/system/` and `cmd/check-isa-level/`. (Minor; agenticolsconfig added for parity with reconciler.md.) ## Structural concerns -1. **how/reconciler.md size** — At 180 lines, this file covers both `controller/agenticrun/` (large) and `controller/console/` (small). This is acceptable given the console section is only ~10 lines, but if the console component grows it should be split into `how/console.md`. - -2. **how/reconciler.md entry point section** — The `cmd/main.go` description (lines 9-15) partially duplicates the new `how/project-structure.md` entry points section. The reconciler.md section should reference project-structure.md for the main binary and focus only on the controller setup flow. +None new. `how/reconciler.md` remains large but cohesive now that the console section is removed. ## Findability issues -None. The cross-reference table in README.md provides clear mapping between what/ and how/ files. The quick-start table covers all common entry points. - -## No issues - -- All spec files have real content (no empty templates or placeholders). -- All `controller/agenticrun/` source files listed in how/reconciler.md module map exist on disk. Deleted files (`sandbox.go`, `bare_pod_manager.go`, `sandbox_templates.go`) removed from map. -- All `cli/run/` source files listed in how/cli.md module map exist on disk. -- All template files (`*.tmpl`) listed in how/reconciler.md exist. -- All CRD types in `api/v1alpha1/*_types.go` are covered by what/crd-api.md. -- Behavioral rules are numbered sequentially in all what/ files. -- `[PLANNED: OLS-XXXX]` markers are used consistently across all what/ files. -- Constraints sections present in all what/ files. -- `CLAUDE.md` has spec pointer. -- `ARCHITECTURE.md` exists at project root. -- Layer READMEs removed; content absorbed into main README. +The audit-logging / webhook implementation files were not discoverable from the how/ module maps (see Missing #1). Addressed by adding entries. + +## Accurate (verified current — no change) + +- `[PLANNED: OLS-3743]` layered-timeout markers: code still has `Agent.spec.timeouts.chatSeconds`, no `escalationSeconds`, and no `LIGHTSPEED_AGENT_TIMEOUT_SECONDS`/`LIGHTSPEED_AGENT_MAX_TURNS` env wiring — still planned. Left unchanged. +- `[PLANNED: OLS-3491]` per-step `instructions`: no `Instructions` field on `AgenticRunStep` in `api/v1alpha1` — still planned. Left unchanged. +- `[PLANNED -- spec.audit]` in `what/audit-logging.md` rules 23–24: no `Audit` field on `AgenticOLSConfig` — still planned. Left unchanged. +- `[PLANNED: OLS-3594]` disableDefaultMCP / MCP auto-injection: not in API — still planned. +- Kill switch (`AgenticOLSConfig`, VAP), templog finalizer, per-step SAs, reader multi-binding, execution outcome override: all match code. + diff --git a/.ai/spec/how/project-structure.md b/.ai/spec/how/project-structure.md index 8ec6e87c..c21306fc 100644 --- a/.ai/spec/how/project-structure.md +++ b/.ai/spec/how/project-structure.md @@ -9,10 +9,9 @@ | `api/v1alpha1/` | `AgenticRun`, `Agent`, `LLMProvider`, `ApprovalPolicy`, `AgenticRunApproval`, result types, `DerivePhase` | CRD type definitions, phase derivation, CEL markers, deepcopy | | `cmd/main.go` | `main`, `scheme` | Operator binary entry point | | `cmd/oc-agentic/main.go` | `main` | CLI binary entry point | -| `controller/agenticrun/` | `AgenticRunReconciler`, `SandboxAgentCaller`, `SandboxManager`, `SandboxLifecycle`, `PodSpecBuilder`, `PodEventHandler` | AgenticRun reconciler, unified sandbox management (SA, RBAC, ConfigMap, pod), pod event handler, timeout loop, results | -| `controller/console/` | `EnsureAgenticConsole`, `AgenticConsoleConfig` | Console plugin deployment (Deployment, Service, ConfigMap, ConsolePlugin CR) | -| `controller/sandbox/` | Legacy bootstrap helpers | SA creation inlined into `cmd/main.go` | -| `pkg/configuration/` | `Config`, `Cache`, `OnConfigMapChange` | ConfigMap-driven config cache (sandbox mode, PodSpec, OTEL, MCP) | +| `controller/agenticrun/` | `AgenticRunReconciler`, `SandboxAgentCaller`, `SandboxManager`, `SandboxLifecycle`, `PodSpecBuilder`, `PodEventHandler`, `AuditLogger`, `AgenticRunApprovalMutator` | AgenticRun reconciler, unified sandbox management (SA, RBAC, ConfigMap, pod), pod event handler, timeout loop, results, audit logging, approval mutating webhook | +| `controller/agenticolsconfig/` | `Reconciler` | `AgenticOLSConfig` reconciler — maintains the `Suspended` status condition (kill switch) | +| `pkg/configuration/` | `Config`, `Cache`, `OnConfigMapChange`, OTel provider | ConfigMap-driven config cache (sandbox mode, PodSpec, OTEL, MCP) and OTLP/audit telemetry provider (`otel_provider.go`) | | `pkg/configwatch/` | `Watcher`, `TryLoad` | Generic ConfigMap watcher utility | | `cli/` | `NewRootCmd` | CLI root command | | `cli/run/` | `CreateOptions`, `ListOptions`, `GetOptions`, `ApproveOptions`, `DenyOptions`, `WatchOptions`, `LogsOptions`, `DeleteOptions` | CLI subcommands for run lifecycle operations | @@ -29,11 +28,11 @@ ## Key Entry Points **Operator binary** (`cmd/main.go`): -- Parses flags (`--namespace`, `--metrics-bind-address`, `--health-probe-bind-address`, `--agentic-console-image`) +- Parses flags (`--namespace`, `--metrics-bind-address`, `--health-probe-bind-address`) - Creates `configuration.Cache` and registers ConfigMap watcher for `lightspeed-agentic-configuration` -- Wires `SandboxManager` → `SandboxAgentCaller` → `AgenticRunReconciler` directly (no `controller/setup.go`) +- Wires `SandboxManager` → `SandboxAgentCaller` → `AgenticRunReconciler` directly (no `controller/setup.go`), plus the `agenticolsconfig.Reconciler` - Ensures `lightspeed-agent` ServiceAccount unconditionally (discovery seed for reader CRBs) -- Registers console plugin, health/readiness probes, and webhook +- Registers health/readiness probes and the `AgenticRunApproval` mutating webhook (`/mutate-agenticrunapproval`) - Starts manager with signal handler **CLI binary** (`cmd/oc-agentic/main.go`): @@ -42,8 +41,7 @@ **Controller setup** (inlined in `cmd/main.go`): - Creates `SandboxManager(client, cfgCache, namespace)` and `SandboxAgentCaller` with dependency injection -- Registers `AgenticRunReconciler` via `SetupWithManager` -- Registers `EnsureAgenticConsole` as a `RunnableFunc` +- Registers `AgenticRunReconciler` and `agenticolsconfig.Reconciler` via `SetupWithManager` - Registers `lightspeed-agent` SA creation as a `RunnableFunc` ## Naming Conventions diff --git a/.ai/spec/how/reconciler.md b/.ai/spec/how/reconciler.md index 70c94416..6e797481 100644 --- a/.ai/spec/how/reconciler.md +++ b/.ai/spec/how/reconciler.md @@ -11,7 +11,7 @@ Audience: AI agents. Behavioral rules and phase semantics live in **what/** spec - Creates `configuration.Cache` (starts nil). Eagerly attempts `configwatch.TryLoad` for the `lightspeed-agentic-configuration` ConfigMap. Registers `configwatch.Watcher` for runtime changes. - Wires **dependency injection** directly (no `controller/setup.go`): - `agenticrun.NewSandboxManager(mgr.GetClient(), cfgCache, namespace, auditLogger)` → `SandboxLifecycle`. - - `&agenticrun.SandboxAgentCaller{Sandbox, K8sClient, ClientFactory, Namespace, Audit}` → satisfies `agenticrun.AgentCaller`. + - `&agenticrun.SandboxAgentCaller{Sandbox, K8sClient, Namespace, Audit}` → satisfies `agenticrun.AgentCaller`. (No `ClientFactory` — HTTP was removed under OLS-3066.) - `agenticrun.AgenticRunReconciler{Client, Agent, Config, Namespace, Audit, TempLog}` → `SetupWithManager(mgr)`. - `agenticolsconfig.Reconciler` → `SetupWithManager(mgr)` — maintains `AgenticOLSConfig` `Suspended` condition. - Ensures `lightspeed-agent` ServiceAccount unconditionally (idempotent create). @@ -29,7 +29,10 @@ Audience: AI agents. Behavioral rules and phase semantics live in **what/** spec | `approval.go` | — | `getApprovalPolicy`, `getAgenticRunApproval`, `ensureAgenticRunApproval`, `isStageApproved`, `isStageDenied`, `getStageOverrideAgent`, `getStageOption` | | `resolve.go` | `resolvedStep`, `resolvedWorkflow` | `resolveAgenticRun`, `stepAgentName` | | `agent.go` | `AgentCaller`, `StubAgentCaller`; `AnalysisOutput`, `ExecutionOutput`, `VerificationOutput`, `EscalationOutput` | Interface methods on `StubAgentCaller` | -| `sandbox_manager.go` | `SandboxManager` | `NewSandboxManager`, `Create`, `Release`, `createBarePod`, `createSandboxClaim`, `releaseBarePod`, `releaseSandboxClaim`, `ensureSA`, `setSAOwner`, `buildInputConfigMap`, `createInputConfigMap`, `podSpecToUnstructured` | +| `sandbox_manager.go` | `SandboxManager` | `NewSandboxManager`, `Create`, `Release`, `createBarePod`, `createSandboxClaim`, `releaseBarePod`, `releaseSandboxClaim`, `ensureSA`, `setSAOwner`, `createInputConfigMap`, `podSpecToUnstructured` | +| `input_configmap.go` | — | `inputConfigMapName`, `buildInputConfigMap`, `buildResultTemplate`, `nextResultIndex` (builds the `/input/` ConfigMap payload and pre-filled Result CR template) | +| `audit.go` | `AuditLogger`, `ProductionAuditLogger`, `NoOpAuditLogger`, `LogEmitter`, `NoOpLogEmitter`, `AgenticRunIDGenerator` | OTel audit span/event emission and templog OTLP log records (see `what/audit-logging.md`, `what/templog.md`) | +| `approval_webhook.go` | `AgenticRunApprovalMutator` | Mutating admission webhook (`/mutate-agenticrunapproval`) — stamps `spec.approver` and emits the approval audit event (see `what/audit-logging.md` rules 17–21) | | `sandbox_agent.go` | `SandboxLifecycle` interface; `SandboxAgentCaller` | `Analyze`, `Execute`, `Verify`, `Escalate`, `ReleaseSandboxes`, `launchSandbox`, `patchSandboxInfo`, `buildAgentContext`, `collectFailedResults`, `stepString` | | `pod_handler.go` | Pod watch handler (methods on `AgenticRunReconciler`); timeout background goroutine | `handlePodEvent`, `completeStep`, `patchStepCondition`, `patchStepResult`, `releaseSandbox`, `runTimeoutLoop`, `handleTimeEvent`, `stepConditionType`, `fetchResultCR`, `podFailMessage` | | `podspec_builder.go` | `PodSpecBuilder`; label constants (`LabelManaged`, `LabelRun`, etc.); MCP env DTOs (`mcpServerEnvEntry`, `mcpHeaderEnvEntry`) | `Build`, `buildSkills`, `buildMCPServers`, `buildRequiredSecrets`, `addProviderSpecificEnv`, `credentialsSecretName`, `providerURL`, `providerTypeString` | @@ -65,17 +68,6 @@ Audience: AI agents. Behavioral rules and phase semantics live in **what/** spec --- -## Module map: `controller/console/` - -| File | Types | Key functions | -|------|-------|----------------| -| `reconciler.go` | `AgenticConsoleConfig` (Image, Namespace); constants for plugin name, cert, nginx config string | `EnsureAgenticConsole` (orchestrates ordered ensures), `labels`, `ensureConfigMap`, `ensureServiceAccount`, `ensureService`, `ensureDeployment`, `ensureConsolePlugin`, `ensureConsoleActivation` | -| `reconciler_test.go` | — | Tests for idempotency, image updates, skip when no image | - -**Integration note:** `EnsureAgenticConsole` is registered in `cmd/main.go` as a `manager.RunnableFunc` — it runs once at manager start, not as a reconcile loop. It mutates OpenShift `Console` cluster CR `spec.plugins` via retry-on-conflict. - ---- - ## Data flow: reconcile loop 1. **Watch / enqueue:** controller-runtime delivers `ctrl.Request` for a `AgenticRun` namespaced name. `SetupWithManager` `Owns` child CRs (`AgenticRunApproval`, `AnalysisResult`, `ExecutionResult`, `VerificationResult`, `EscalationResult`), `Owns` Pods and ConfigMaps [OLS-3066], and **Watches** cluster `ApprovalPolicy` and `AgenticOLSConfig` to enqueue all non-terminal runs when either changes. [OLS-3066] Pod watches serve **failure detection** (pod `Failed`, `ImagePullBackOff`); Result CR watches serve **completion detection** (CR created with `Completed` condition). @@ -205,7 +197,7 @@ AgenticRunReconciler.Reconcile ## Implementation notes (gotchas) -- **`cmd/main.go` scheme:** Registers core + `agenticv1alpha1` + `consolev1` + `openshiftv1`. No separate `controller/setup.go` — all wiring is inline in `main.go`. Watching or applying arbitrary CRDs from tests may need extended schemes (see `reconciler_test.go`). +- **`cmd/main.go` scheme:** Registers client-go core + `agenticv1alpha1` only (the `consolev1` / `openshiftv1` schemes were removed with the console plugin — OLS-3236/OLS-3350). No separate `controller/setup.go` — all wiring is inline in `main.go`. Watching or applying arbitrary CRDs from tests may need extended schemes (see `reconciler_test.go`). - **Max concurrent reconciles:** `SetupWithManager` reads cluster `ApprovalPolicy` via API reader for `MaxConcurrentRuns`, else `DefaultMaxConcurrentRuns` from API package. - **Policy watch:** Enqueues **all** non-terminal runs on any `ApprovalPolicy` event — can be chatty. - **AgenticOLSConfig watch:** Same pattern as policy watch — enqueues all non-terminal runs on any `AgenticOLSConfig` change. When `suspended` flips to `true`, all re-queued runs hit the suspension guard and get terminated. diff --git a/.ai/spec/what/crd-api.md b/.ai/spec/what/crd-api.md index 9fed86ac..82567a74 100644 --- a/.ai/spec/what/crd-api.md +++ b/.ai/spec/what/crd-api.md @@ -12,9 +12,9 @@ Kubernetes API surface for the agentic operator. **Lifecycle and gates** are in 6. **AgenticRun — `spec.revisionFeedback`**: User-mutable spec field for iterative feedback; when set/non-empty and `metadata.generation` advances beyond the analyzed condition’s `observedGeneration`, operators MUST trigger re-analysis per `run-lifecycle.md`. `spec.ttlAfterTerminal` (rule 6a) is the only other mutable spec field; the controller MUST advance `Analyzed.observedGeneration` in the same write whenever it patches `ttlAfterTerminal`, so that its own generation bump is never misread as an outstanding revision request. 6a. **AgenticRun — `spec.ttlAfterTerminal`**: Optional time-to-live in seconds after the run reaches a terminal state (see `run-lifecycle.md` rule 4 for the terminal set), after which the operator deletes the `AgenticRun` CR (Kubernetes GC cascades to owned resources via owner references). Mutable — adapters or admins MAY pre-set it before the run reaches terminal state; once terminal, if unset, the operator stamps it from `AgenticOLSConfig.spec.lifecycle.terminalTTL` (cluster default) without overwriting a pre-set value. `0` explicitly disables auto-deletion for that run. When omitted and no cluster default exists, no automatic deletion occurs (backwards-compatible). See `run-lifecycle.md` rule 23. 6b. **AgenticRun — `status.terminalTime`**: Timestamp the operator stamps once, the first time a run reaches a terminal state; not updated again while the run remains terminal. Cleared by the revision handler when a terminal run re-enters analysis (rule 6/23), so a subsequent terminal phase gets a fresh timestamp instead of reusing the prior terminal event's. Used with `spec.ttlAfterTerminal` to compute the deletion deadline. -6c. [PLANNED: OLS-3661] **`TokenUsage` struct**: Embedded struct with two required fields: `inputTokens` (int64, >= 0) and `outputTokens` (int64, >= 0). Both fields are required whenever the struct is present. `TokenUsage` carries token consumption data at the granularity of a single step (on Result CRs) or an entire run (on `AgenticRunStatus`). -6d. [PLANNED: OLS-3661] **AgenticRun — `status.tokenUsage`**: Optional `TokenUsage` (rule 6c). Cumulative input and output token counts across all completed steps of the run. The operator sets this field by aggregating `status.tokenUsage` from individual Result CRs (see `sandbox-execution.md` rule 43.1); users MUST NOT modify it. When no steps have completed, the field is absent (not zero-valued). -6e. [PLANNED: OLS-3661] **Result CR — `status.tokenUsage`**: All Result CR kinds (`AnalysisResult`, `ExecutionResult`, `VerificationResult`, `EscalationResult`) gain an optional `status.tokenUsage` (`TokenUsage`, rule 6c) field. The sandbox populates this field with per-step token counts before publishing the Result CR (see sandbox `run-api.md` rule 21). The operator reads it during result processing for run-level aggregation (see `sandbox-execution.md` rule 43.1). +6c. [DONE: OLS-3661/OLS-3993] **`TokenUsage` struct**: Embedded struct with two required fields: `inputTokens` (int64, >= 0) and `outputTokens` (int64, >= 0), both `+required` with `MinProperties=1` on the struct. Both fields are required whenever the struct is present (uses the `omitzero`/`IsZero()` pattern so the zero value is omitted from serialization). `TokenUsage` carries token consumption data at the granularity of a single step (on Result CRs) or an entire run (on `AgenticRunStatus`). +6d. [DONE: OLS-3661/OLS-3993] **AgenticRun — `status.tokenUsage`**: Optional `TokenUsage` (rule 6c). Cumulative input and output token counts across all completed steps of the run. The operator sets this field by aggregating `status.tokenUsage` from individual Result CRs (see `sandbox-execution.md` rule 43.1); users MUST NOT modify it. When no steps have completed, the field is absent (not zero-valued). +6e. [DONE: OLS-3661/OLS-3993] **Result CR — `status.tokenUsage`**: All Result CR kinds (`AnalysisResult`, `ExecutionResult`, `VerificationResult`, `EscalationResult`) have an optional `status.tokenUsage` (`TokenUsage`, rule 6c) field. The sandbox populates this field with per-step token counts before publishing the Result CR (see sandbox `run-api.md` rule 21). The operator reads it during result processing for run-level aggregation (see `sandbox-execution.md` rule 43.1). 7. **AgenticRun — `spec.targetNamespaces`**: Optional list of namespaces for context and RBAC targeting; immutable once set; when empty, RBAC targeting MAY fall back to namespaces declared in analysis RBAC output at execution time (see `sandbox-execution.md`). 8. **AgenticRun — `spec.analysisOutput`**: Immutable after set. `mode` defaults to full analysis schema when empty/default. `mode=Minimal` REQUIRES `schema` to be set, forbids `spec.execution` and `spec.verification`, and restricts option shape accordingly. 9. **AgenticRun — `spec.tools`**: Default `ToolsSpec` for all steps; immutable once set. Per-step `tools` on `spec.analysis` / `spec.execution` / `spec.verification` replaces the default for that step only when non-zero. @@ -72,7 +72,7 @@ Kubernetes API surface for the agentic operator. **Lifecycle and gates** are in - `metadata.*` - `spec.request`, `spec.targetNamespaces`, `spec.revisionFeedback`, `spec.ttlAfterTerminal`, `spec.analysisOutput`, `spec.tools`, `spec.analysis`, `spec.execution`, `spec.verification` - `spec.analysis.instructions`, `spec.execution.instructions`, `spec.verification.instructions` [PLANNED: OLS-3491] -- `status.conditions`, `status.steps.analysis|execution|verification|escalation.*`, `status.terminalTime`, `status.tokenUsage` [PLANNED: OLS-3661] +- `status.conditions`, `status.steps.analysis|execution|verification|escalation.*`, `status.terminalTime`, `status.tokenUsage` ### Agent - `metadata.name`, `spec.llmProvider.name`, `spec.model`, `spec.reasoningConfig`, `spec.timeouts.*`, `spec.maxTurns`, `status.conditions` @@ -103,7 +103,7 @@ Kubernetes API surface for the agentic operator. **Lifecycle and gates** are in - `SecretRequirement`: `name`, `description`, `mountAs.*` - `StepResultRef`: `name`, `outcome` - `SandboxInfo`: `claimName`, `namespace` -- `TokenUsage`: `inputTokens`, `outputTokens` [PLANNED: OLS-3661] +- `TokenUsage`: `inputTokens`, `outputTokens` ## Constraints @@ -119,5 +119,5 @@ Kubernetes API surface for the agentic operator. **Lifecycle and gates** are in - [DONE: OLS-3295] Renamed `Proposal` → `AgenticRun`, `ProposalApproval` → `AgenticRunApproval` CRD kinds and all associated field names, RBAC resources, and label keys. - [PLANNED: OLS-3594] Optional `disableDefaultMCP` (and related auto-injection) — deferred; blocked by OLS-3526 and OLS-3572. Not near-term. - [DONE: OLS-3566] Added `AgenticOLSConfig.spec.lifecycle.terminalTTL` (cluster default) and `AgenticRun.spec.ttlAfterTerminal` / `status.terminalTime` (per-run override + stamp) for automatic terminal-run cleanup. Added `oc agentic run cleanup` CLI command for manual batch cleanup (see `how/cli.md`). -- [PLANNED: OLS-3661] `TokenUsage` struct (`inputTokens`, `outputTokens`) on Result CR statuses and `AgenticRunStatus.tokenUsage` for run-level aggregation. Sandbox populates per-step counts; operator aggregates on Result CR completion. See rules 6c–6e, 31–34, and `sandbox-execution.md` rule 43.1. +- [DONE: OLS-3661/OLS-3993] `TokenUsage` struct (`inputTokens`, `outputTokens`) on Result CR statuses and `AgenticRunStatus.tokenUsage` for run-level aggregation. Sandbox populates per-step counts; operator aggregates on Result CR completion (`controller/agenticrun/results.go`). See rules 6c–6e, 31–34, and `sandbox-execution.md` rule 43.1. - [PLANNED: OLS-3743] Replace unwired `spec.timeouts.chatSeconds` with `spec.timeouts.escalationSeconds`; wire all step budgets and `spec.maxTurns` to the batch sandbox with operator-owned defaults. diff --git a/.ai/spec/what/sandbox-execution.md b/.ai/spec/what/sandbox-execution.md index 4f313806..d106b48b 100644 --- a/.ai/spec/what/sandbox-execution.md +++ b/.ai/spec/what/sandbox-execution.md @@ -83,7 +83,7 @@ Behavioral specification for how workflow steps run inside ephemeral **sandboxes ### Operator Re-entry Logic [OLS-3066] 43. **Re-entry decision tree**: On each Reconcile, for each in-progress step, the controller MUST evaluate in this order: (1) Run-level condition for this step is `True` or `False` → step complete, skip. (2) Result CR exists for this step (label selector `agentic.openshift.io/run` + `agentic.openshift.io/step`) with `Completed=True` in status conditions → process result, update run conditions, cleanup pod + ConfigMap. (3) Result CR exists but NO `Completed` condition → still being written, wait (normally `RequeueAfter(30s)`; [PLANNED: OLS-3743] bounded by time remaining to the hard running deadline). (4) No Result CR — check pod status per rules 43a–43d). -43.1. [PLANNED: OLS-3661] **Token usage aggregation on result processing**: When processing a completed Result CR (rule 43 item 2), the operator MUST read `status.tokenUsage` from the Result CR (see `crd-api.md` rule 6e). If `status.tokenUsage` is present on the Result CR, the operator MUST add the Result CR's `inputTokens` and `outputTokens` to the `AgenticRun`'s `status.tokenUsage` cumulative totals (see `crd-api.md` rule 6d). If the `AgenticRun`'s `status.tokenUsage` does not yet exist, it MUST be initialized from the Result CR's values. This aggregation MUST happen in the same status patch that updates run conditions for the completed step. If `status.tokenUsage` is absent on the Result CR (sandbox did not report tokens), the operator MUST skip aggregation for that step — it MUST NOT zero-initialize or error. +43.1. [DONE: OLS-3661/OLS-3993] **Token usage aggregation on result processing**: When processing a completed Result CR (rule 43 item 2), the operator MUST read `status.tokenUsage` from the Result CR (see `crd-api.md` rule 6e). If `status.tokenUsage` is present on the Result CR, the operator MUST add the Result CR's `inputTokens` and `outputTokens` to the `AgenticRun`'s `status.tokenUsage` cumulative totals (see `crd-api.md` rule 6d). If the `AgenticRun`'s `status.tokenUsage` does not yet exist, it MUST be initialized from the Result CR's values. This aggregation MUST happen in the same status patch that updates run conditions for the completed step. If `status.tokenUsage` is absent on the Result CR (sandbox did not report tokens), the operator MUST skip aggregation for that step — it MUST NOT zero-initialize or error. 43a. **Pod not found, first entry**: Create input ConfigMap and Pod/SandboxClaim. Set step condition to `Unknown` with reason `WaitingForSandbox`. Patch `status.steps..sandbox.claimName`. Return `RequeueAfter(30s)`. 43b. **Pod Pending**: Check for `ImagePullBackOff` → fail immediately. [PLANNED: OLS-3743] Check the five-minute startup deadline → release the sandbox with `SandboxStartupTimeout` if exceeded. Otherwise wait and requeue after the smaller of 30 seconds or the remaining startup budget. 43c. **Pod Running**: [PLANNED: OLS-3743] Compute the hard deadline from the main container `startedAt`, the effective Agent step budget, and the one-minute margin. Release the sandbox with `SandboxTimeout` if exceeded. Otherwise wait and requeue after the smaller of 30 seconds or the remaining running budget. @@ -145,5 +145,5 @@ Behavioral specification for how workflow steps run inside ephemeral **sandboxes - [DONE: OLS-3685/OLS-3686] Inter-operator configuration handoff — `PodSpecBuilder` reads a base `corev1.PodSpec` from the `lightspeed-agentic-configuration` ConfigMap (produced by lightspeed-operator) and applies all per-run config through a single overlay code path. Eliminated duplication between `PodSpecBuilder` (bare-pod) and `EnsureAgentTemplate` (sandbox-claim) — unified `SandboxManager` builds the complete PodSpec, then the mode determines delivery. CLI flags `--sandbox-mode`, `--agentic-sandbox-image`, `--image-pull-policy` replaced by ConfigMap keys. No-blocking startup; graceful degradation when ConfigMap is absent. See `docs/inter-operator-handoff-design.md`. - [PLANNED: OLS-3594] Optional default ocp-mcp auto-injection into sandbox pods — deferred; product value unconfirmed. Blocked by OLS-3526 (standalone HTTPS ocp-mcp) and OLS-3572 (inter-operator config handoff). Not near-term. - [PLANNED: OLS-3491] Configurable step `instructions` (system channel) separate from step `query` input; create-time materialization; cluster defaults via handoff ConfigMap. See rules 7, 11–13b and `crd-api.md` rules 10a–10f. -- [PLANNED: OLS-3661] Token usage aggregation — operator reads `status.tokenUsage` from completed Result CRs and accumulates into `AgenticRun.status.tokenUsage`. See rule 43.1 and `crd-api.md` rules 6c–6e. +- [DONE: OLS-3661/OLS-3993] Token usage aggregation — operator reads `status.tokenUsage` from completed Result CRs and accumulates into `AgenticRun.status.tokenUsage` (`controller/agenticrun/results.go`). See rule 43.1 and `crd-api.md` rules 6c–6e. - [PLANNED: OLS-3743] Layer Agent-configured cooperative execution budgets under fixed operator sandbox startup and hard running deadlines; wire `maxTurns`; distinguish timeout sources in status. diff --git a/.ai/spec/what/system-overview.md b/.ai/spec/what/system-overview.md index c9b8fc9f..a52f5bb5 100644 --- a/.ai/spec/what/system-overview.md +++ b/.ai/spec/what/system-overview.md @@ -17,8 +17,8 @@ The lightspeed-agentic-operator is a Kubernetes operator that watches `AgenticRu - **AgenticRun controller** — reconciles `AgenticRun` CRs through the workflow state machine. - **CLI plugin** (`oc-agentic`) — provides `oc agentic run` commands for run CRUD, approval, watch, and log streaming. - **API types** (`api/v1alpha1`) — CRD type definitions published as a separate Go module for downstream consumers. -5a. [PLANNED: OLS-3236] The **console plugin** deployment is migrated to the lightspeed-operator for full reconciliation lifecycle management. The agentic-operator no longer deploys any console plugins. The **alerts adapter** deployment is also managed by the lightspeed-operator. -6. The run controller runs in the operator binary via `controller.Setup()`. [PLANNED: OLS-3236] The console plugin `RunnableFunc` and `controller/console/` package are removed. +5a. [DONE: OLS-3236/OLS-3350] The **console plugin** deployment is managed by the lightspeed-operator for full reconciliation lifecycle management. The agentic-operator does not deploy any console plugins. The **alerts adapter** deployment is also managed by the lightspeed-operator. +6. The run controller runs in the operator binary, wired inline in `cmd/main.go` (no `controller/setup.go`). [DONE: OLS-3236/OLS-3350] The console plugin `RunnableFunc` and `controller/console/` package have been removed. 7. The CLI is a separate binary (`cmd/oc-agentic`) that communicates directly with the Kubernetes API server. ### External Dependencies @@ -27,7 +27,7 @@ The lightspeed-agentic-operator is a Kubernetes operator that watches `AgenticRu 9. When `sandbox-mode=sandbox-claim` (from `lightspeed-agentic-configuration` ConfigMap), the operator MUST interact with the Sandbox API (`extensions.agents.x-k8s.io/v1alpha1` `SandboxClaim`, `agents.x-k8s.io/v1alpha1` `Sandbox`) to provision ephemeral agent workloads. In the default `bare-pod` mode, the operator creates Pods directly and does not depend on Sandbox API CRDs. 10. The operator MUST resolve `Agent` CRs and their referenced `LLMProvider` CRs to determine model configuration and credentials for each workflow step. 11. The operator MUST call the sandbox agent's `POST /v1/agent/run` HTTP endpoint for each workflow step (analysis, execution, verification, escalation). -12. [PLANNED: OLS-3236] Console plugin deployment is migrated to the lightspeed-operator. The agentic-operator no longer interacts with OpenShift Console APIs for plugin deployment. +12. [DONE: OLS-3236/OLS-3350] Console plugin deployment is managed by the lightspeed-operator. The agentic-operator does not interact with OpenShift Console APIs for plugin deployment (the manager scheme registers only client-go and `agenticv1alpha1` types). ### Dual-Module Structure @@ -54,7 +54,6 @@ The lightspeed-agentic-operator is a Kubernetes operator that watches `AgenticRu - The operator assumes it is the sole controller for `agentic.openshift.io/v1alpha1` resources; running multiple replicas without leader election would cause conflicts. - Sandbox provisioning via `SandboxClaim` depends on the Sandbox API CRDs being installed in the cluster; this dependency only applies when `sandbox-mode=sandbox-claim` in the ConfigMap. The default `bare-pod` mode has no external CRD dependency. - The `lightspeed-agentic-configuration` ConfigMap must be created by lightspeed-operator before any AgenticRun can execute. The operator does not block startup on this ConfigMap — it starts normally and individual runs fail gracefully when the ConfigMap is missing. -- The operator requires OpenShift APIs for console plugin deployment; running on vanilla Kubernetes skips console integration. ## Planned Changes @@ -62,5 +61,5 @@ The lightspeed-agentic-operator is a Kubernetes operator that watches `AgenticRu |---|---| | OLS-2957 | Sandbox template management UX and CRD ergonomics may change operator/template coupling | | OLS-2940 | Autonomous workflow CRD migrations may rename or reshape `v1alpha1` fields | -| OLS-3236 | Remove `controller/console/` package and `--agentic-console-image` flag. Console plugin and alerts adapter deployment moves to lightspeed-operator. | +| OLS-3236/OLS-3350 | [DONE] Removed `controller/console/` package and `--agentic-console-image` flag. Console plugin and alerts adapter deployment moved to lightspeed-operator. | | OLS-3685/3686 | [DONE] Inter-operator config handoff: unified `SandboxManager` reads base PodSpec from `lightspeed-agentic-configuration` ConfigMap. Sandbox mode, image, and PodSpec all sourced from ConfigMap. CLI flags removed. No-blocking startup; graceful degradation. | diff --git a/.ai/spec/what/templog.md b/.ai/spec/what/templog.md index cd2fb890..b9745585 100644 --- a/.ai/spec/what/templog.md +++ b/.ai/spec/what/templog.md @@ -54,5 +54,6 @@ Implementation details for the agentic-operator's role in the templog feature. - `what/audit-logging.md` — Audit event catalog, structured JSON format, OTEL span hierarchy - `what/run-lifecycle.md` — AgenticRun CR lifecycle, phase transitions, finalizers -- `pkg/telemetry/` — Provider implementation (ConfigMap reader, OTLP exporters, admin HTTP client) +- `pkg/configuration/otel_provider.go` — OTLP exporter / telemetry provider (ConfigMap reader, OTLP exporters, admin HTTP client) +- `controller/agenticrun/audit.go` — `AuditLogger` / `LogEmitter` (span + OTLP log emission) - `pkg/configwatch/` — Generic informer-based ConfigMap watcher