Files
kandev/docs/specs/executors/system-design/kubernetes-retained-compute.md
T
2026-09-10 11:05:05 +01:00

7.7 KiB

status, system, requirements
status system requirements
current executors
REQ-EXECUTORS-K8S-RETAINED-001
REQ-EXECUTORS-K8S-RETAINED-002

Kubernetes Retained Compute Visibility System Design

Purpose and boundaries

The requirements extend the existing executor session projection. The feature does not introduce a resource inventory or infer process activity from Kubernetes readiness.

Requirement mapping

Requirement Design section
REQ-EXECUTORS-K8S-RETAINED-001 Backend projection and classification
REQ-EXECUTORS-K8S-RETAINED-002 Permissions and responsive presentation

Backend projection and classification

internal/kubernetes/sessions.go already retrieves the task session, checks task access, and gets the exact recorded Pod. Extend SessionRow at that seam. The HTTP sessions route and kubernetes.sessions.list share the same projection. Current fields retain their meaning. New fields are additive:

Field Meaning
session_state Canonical known TaskSession.State, otherwise unknown
retention_state active, retained, terminating, terminal, missing, or unknown
main_container_requests.cpu Optional canonical Kubernetes quantity string
main_container_requests.memory Optional canonical Kubernetes quantity string

The request object appears only after exact identity verification and a matching main container. It contains only CPU and memory, never a complete resource map. The UI labels these fields as main-container requests. It does not aggregate them or call them usage, reserved cluster capacity, or cost.

Classification follows this precedence:

  1. Invalid inventory, failed access, malformed states, a missing main container, or identity mismatch yields unknown.
  2. An exact recorded-Pod GET returning NotFound yields missing.
  3. A verified Pod with a deletion timestamp yields terminating.
  4. A verified Pod in Succeeded or Failed phase yields terminal.
  5. A Pending or Running Pod plus session CANCELLED, COMPLETED, FAILED, or IDLE yields retained.
  6. A Pending or Running Pod plus session CREATED, STARTING, RUNNING, or WAITING_FOR_INPUT yields active.
  7. Any remaining combination yields unknown.

CANCELLED maps to stopped-session wording. Other retained session states keep their distinct session labels. WAITING_FOR_INPUT is never labeled stopped. The term active denotes the recorded session category, not verified agent connectivity. An Office IDLE session can still retain Kubernetes resources under the current executor policy. Neither category establishes whether a terminal or background process exists.

Derivation uses TaskSession.State, not executors_running.Status, task workflow columns, or container readiness. The existing endpoint enumerates inventory rows without discarding them solely because the agent session stopped. Keep that behavior so ordinary Stop cannot hide its retained Pod.

Task state and Pod state are separate observations. The projection does not promise an atomic cross-system snapshot. The next refresh resolves concurrent lifecycle changes. No new observation timestamp uses TaskSession.UpdatedAt as a false stopped-since clock.

Permissions and failure behavior

Existing task authorization and identity checks remain before Pod projection. New fields do not bypass executor/task/session filters or expand Kubernetes RBAC. The backend performs no additional Pod GET, list, metrics, log, or Event request. The admin-only session-impact response remains count-only with its existing semantics. This feature adds no global count, including for administrators.

An access or identity error omits resource requests and uses unknown. An exact NotFound uses missing while preserving the existing sanitized failure field. Raw session errors and Pod spec content never enter the response. An unavailable client remains an endpoint error rather than an empty success.

Responsive presentation

Extend KubernetesSession in lib/types/http-kubernetes.ts and the existing API tests. New fields are optional in TypeScript for old responses and fixture compatibility. The backend owns classification. Frontend helpers select translated labels and fallbacks, without recreating the state machine.

KubernetesSessionsCard remains the only changed product surface. Desktop keeps the table. Each default row uses at most two status lines. The first line shows session and retention badges. The second line shows distinct Pod phase and main-container state values. The Pod cell also shows the workspace mode, and a separate column shows the main-container requests. A disclosure opens one labeled diagnostic row without changing another session row. The task identity becomes a routing-adapter link to /t/<encoded-task-id>. It does not select or resume a session automatically.

Phone presentation reuses the shipped MobileSessionList cards in this file and the direct-navigation pattern from components/kanban-with-preview.tsx. Each card groups Pod identity, task and session identity, compact status, requests, workspace mode, and creation time. The status uses the same two-line hierarchy as the desktop row. The phone card has no diagnostic disclosure. The card body navigates to its task because there are no competing inline actions. The whole card is a semantic link with at least a 44px touch height. The page remains the single vertical scroll owner. Long identifiers wrap. No drawer, extra navigation step, nested vertical scroller, or fixed footer is needed. Desktop link density remains unchanged. Focus indicators and accessible names identify the task and session on both viewports.

Visible card-level guidance explains Stop retention and Archive/Delete workspace consequences. It also states that requests exclude sidecars and do not show actual use. No direct destructive action is added. Existing task routes own those actions and confirmations.

useKubernetesSessions retains its 90-second poll and manual refresh behavior. Refresh failures must remain visible. A stale prior row must not appear as current confirmed retention. Existing executor-scope generation guards discard late responses. Missing new fields use unknown/unspecified labels, not inferred defaults.

New copy uses executors translation keys in English, Portuguese, and Chinese catalogs. Traditional Chinese derives through the existing converter. Pseudo-locale tests cover expansion without translating state discriminants or Kubernetes quantities.

Verification and persistence

Backend tables cover every session state, Pod phase, deletion, NotFound, access error, identity mismatch, missing request, explicit zero request, and admission-mutated request. Actual Pod values win over current profile values and the original template. HTTP and WebSocket responses share field tests. Fake-client action counts prove unauthorized rows trigger no Pod read and visible rows require one exact GET.

Component tests cover optional fields, distinct labels, links, loading, and errors. Desktop and mobile E2E extend the existing Kubernetes configuration specs. They verify navigation, safe guidance, responsive geometry, and post-refresh changes. A Kind lifecycle scenario proves Stop retains the Pod and refresh shows it, then Resume clears the retained category without replacing the Pod.

No schema, lifecycle, poller, feature-toggle, or credential change is required. Public documentation changes describe the new fields and retained-resource wording.