Skip to content

Warm Pool Feasibility Study [Spec]#3

Open
rhuss wants to merge 5 commits into
mainfrom
6111-warm-pool-feasibility
Open

Warm Pool Feasibility Study [Spec]#3
rhuss wants to merge 5 commits into
mainfrom
6111-warm-pool-feasibility

Conversation

@rhuss

@rhuss rhuss commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Why This Change

OpenShell's Kubernetes driver creates a fresh Sandbox CR for every sandbox request, paying 8-12 seconds for pod scheduling, image pull, init container execution, supervisor startup, and gateway registration. For agent harnesses like OpenClaw that create sandboxes per tool call, this latency is unusable. The upstream Agent Sandbox project (v0.5.0) provides extension CRDs for warm pooling (SandboxTemplate, SandboxWarmPool, SandboxClaim), but OpenShell has no awareness of these. We need to know if warm pooling can deliver sub-2s sandbox startup on OpenShift before investing in integration work.

What Changes

This study will create an experiments/ directory with shell-based measurement scripts, Kubernetes manifests for warm pool configurations, and a minimal Go sidecar binary for readiness experiments. It will provision a short-lived ROSA HCP cluster, run 6 experiments measuring cold-start vs warm pool latency across readiness configurations, and produce an RFC in rfc/ with data-backed architectural recommendations for OpenShell warm pool integration. No changes to OpenShell core code. This PR contains the specification artifacts only; implementation follows after spec approval.

How It Works

The study uses a layered measurement approach across 4 execution phases:

  1. Cluster Setup: ROSA HCP with 3 worker nodes, Red Hat Agent Sandbox tech preview operator (upstream fallback), OpenShell via Helm chart, image pre-pulling
  2. Measurement Library: Shared shell functions for timestamp capture, CSV output, pod event collection, p50/p90 computation
  3. Experiments: Cold-start baseline, warm pool claims (default/aggressive probes), Pod Readiness Gates, sidecar readiness, env var injection, combined best-config
  4. RFC: Results compiled into standalone RFC following the OpenShell RFC template

Important

Review Guide contains the full review guidance: key decisions, scope boundaries, areas needing attention, and review checklist.

This PR contains the specification artifacts for Warm Pool Feasibility Study. Implementation follows after spec approval.

Assisted-By: 🤖 Claude Code


Open in Devin Review

Summary by CodeRabbit

  • Documentation
    • Added a complete warm-pool feasibility study set (overview, experiment plans, requirements/checklists, data model, quickstart, review findings, results report, and an architecture-focused RFC).
    • Added a reusable project constitution template.
  • New Features
    • Introduced warm-pool and cold-start measurement tooling with shared Bash utilities, multiple experiment runners, and supporting Kubernetes manifests.
    • Added a readiness sidecar container (including build and image workflow) and collected results artifacts.
  • Chores
    • Updated ignore rules for local/speculative files and adjusted the docs-sync workflow version.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds warm-pool study documentation, Kubernetes experiment tooling and manifests, a readiness sidecar implementation, recorded results, an RFC proposal, repository ignore rules, and a workflow action update.

Changes

Warm Pool Study Planning

Layer / File(s) Summary
Study specifications and planning
brainstorm/*, .specify/memory/constitution.md, specs/001-warm-pool-feasibility/...
Adds feasibility framing, cluster and measurement plans, requirements, data model, research, quickstart, tasks, reviewer guidance, constitution template, ignore rules, and review findings.

Warm Pool Experiment Tooling

Layer / File(s) Summary
Measurement foundation and fixtures
experiments/lib/*, experiments/manifests/*, experiments/results/README.md, experiments/results/.gitignore
Adds timestamp, CSV, event, adoption, cleanup, statistics, and readiness helpers with Kubernetes manifests and result organization guidance.
Measurement scripts
experiments/measure-*.sh
Adds cold-start, warm-pool, combined readiness, environment-injection, readiness-gate, and sidecar-readiness experiment runners.
Readiness sidecar build
experiments/sidecar/*
Adds the Go readiness server, static container image, module metadata, and build/push targets.

Results and Integration Proposal

Layer / File(s) Summary
Experiment results and event artifacts
experiments/RESULTS.md, experiments/results/2026-07-09-rosa-hcp-422/*.json
Adds reproducibility instructions, event snapshots, measured cold-start and warm-pool results, environment-injection observations, limitations, and integration recommendations.
Warm-pool integration RFC
rfc/NNNN-warm-pool-feasibility/README.md
Describes proposed warm-pool behavior across the Kubernetes driver, supervisor, gateway, sandbox state machine, Helm configuration, RBAC, CLI, and documentation.

Workflow Update

Layer / File(s) Summary
Setup uv pin
.github/workflows/sync-docs.yml
Updates the documentation synchronization workflow to use a newer pinned setup-uv action revision.

Estimated code review effort: 4 (Complex) | ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately reflects the main change: adding a warm pool feasibility study specification set.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 6111-warm-pool-feasibility

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

coderabbitai[bot]

This comment was marked as resolved.

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

rhuss added a commit that referenced this pull request Jul 9, 2026
Applied fixes from bot review comments:
- Comment #3552516629: run sidecar container as non-root (USER 65532)
- Comment #3552516599: handle kubectl exec failure in sidecar-readiness
- Comment #3552515048: fix readiness gate condition type mismatch
- Comment #3552514809: align CSV header labels with actual phase data

Assisted-By: 🤖 Claude Code
Signed-off-by: Roland Huß <rhuss@redhat.com>
devin-ai-integration[bot]

This comment was marked as resolved.

rhuss added a commit that referenced this pull request Jul 9, 2026
Extract wait_pool_replenished to lib/common.sh and add replenishment
checks before each claim in measure-combined.sh and
measure-env-injection.sh. Without this, later runs may exhaust the
pool and silently fall back to cold-start provisioning, corrupting
warm pool measurement data.

Assisted-By: 🤖 Claude Code
Signed-off-by: Roland Huß <rhuss@redhat.com>
devin-ai-integration[bot]

This comment was marked as resolved.

@rhuss
rhuss force-pushed the 6111-warm-pool-feasibility branch from 22c9126 to 709b0f8 Compare July 9, 2026 15:42
coderabbitai[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
experiments/measure-cold-start.sh (1)

148-217: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Vanilla runner ignores --image override; SANDBOX_IMAGE is unused.

The --image CLI option is documented in usage() and SANDBOX_IMAGE is defined at line 12, but the vanilla runner hardcodes registry.k8s.io/pause:3.10 in the inline manifest (line 175) instead of using $SANDBOX_IMAGE. The flag has no effect on this configuration, which is misleading for experimenters who pass --image expecting it to apply.

🔧 Proposed fix: use SANDBOX_IMAGE in vanilla manifest
     if ! kubectl apply -n "$NAMESPACE" -f - <<YAML
 apiVersion: agents.x-k8s.io/v1beta1
 kind: Sandbox
 metadata:
   name: ${sandbox_name}
 spec:
   podTemplate:
     spec:
       containers:
       - name: sandbox
-        image: registry.k8s.io/pause:3.10
+        image: ${SANDBOX_IMAGE}
         command: ["/pause"]
 YAML
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@experiments/measure-cold-start.sh` around lines 148 - 217, The vanilla runner
currently hardcodes the sandbox image in run_vanilla_config, so the --image
override and SANDBOX_IMAGE setting are ignored for this path. Update the inline
Sandbox manifest in run_vanilla_config to reference SANDBOX_IMAGE instead of the
fixed pause image, and keep the rest of the create/wait/cleanup flow unchanged
so the existing CLI option applies consistently to vanilla runs.
🧹 Nitpick comments (3)
rfc/NNNN-warm-pool-feasibility/README.md (1)

252-255: 🚀 Performance & Scalability | 🔵 Trivial

Check the operational cost of a 1s kubelet sync.

This target depends on a cluster-wide kubelet flag, not just an OpenShell setting. Verify that OpenShift can absorb the extra propagation churn; otherwise the Phase 1/2 latency goals should not assume sub-second annotation propagation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rfc/NNNN-warm-pool-feasibility/README.md` around lines 252 - 255, The note in
the projected-volume propagation guidance assumes sub-second annotation updates
from kubelet, but the reviewer is asking to verify the operational impact of
using a 1s kubelet sync before treating that latency as feasible. Update the
section around the kubelet propagation and polling fallback text to explicitly
state that `--sync-frequency=1s` is a cluster-wide kubelet setting, and qualify
the Phase 1/2 latency goals unless OpenShift capacity/overhead has been
validated; keep the fallback polling mention tied to the supervisor behavior.
experiments/manifests/readiness-gate-pod.yaml (1)

9-15: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Add a securityContext to the sandbox container.

Static analysis flags missing readOnlyRootFilesystem, default security context, and missing allowPrivilegeEscalation: false. For experiment pods these are non-exploitable, but adding a restrictive security context is cheap and aligns with Kubernetes hardening best practices.

🛡️ Proposed security context
   - name: sandbox
     image: registry.k8s.io/pause:3.10
     command: ["/pause"]
+    securityContext:
+      readOnlyRootFilesystem: true
+      allowPrivilegeEscalation: false
+      runAsNonRoot: true
+      runAsUser: 65534
     resources:
       requests:
         cpu: "100m"
         memory: "64Mi"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@experiments/manifests/readiness-gate-pod.yaml` around lines 9 - 15, Add a
restrictive securityContext to the sandbox container in the readiness-gate pod
manifest so the container uses a hardened default. Update the sandbox container
spec to explicitly set readOnlyRootFilesystem and allowPrivilegeEscalation:
false, and align any other default security settings needed for this pod. Use
the sandbox container block in the manifest to locate the change.

Source: Linters/SAST tools

experiments/manifests/sidecar-readiness.yaml (1)

27-36: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Add a securityContext to the sandbox container.

Same as the readiness-gate-pod manifest — static analysis flags missing readOnlyRootFilesystem and default security context. Cheap to add for experiment pods.

🛡️ Proposed security context
   - name: sandbox
     image: registry.k8s.io/pause:3.10
     command: ["/pause"]
+    securityContext:
+      readOnlyRootFilesystem: true
+      allowPrivilegeEscalation: false
+      runAsNonRoot: true
+      runAsUser: 65534
     volumeMounts:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@experiments/manifests/sidecar-readiness.yaml` around lines 27 - 36, Add a
securityContext to the sandbox container in the sidecar readiness manifest,
matching the readiness-gate-pod manifest’s container hardening. Update the
sandbox container definition to explicitly set the same default security
settings, including readOnlyRootFilesystem, so the experiment pod passes static
analysis and uses the intended secure runtime profile.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@experiments/manifests/sidecar-readiness.yaml`:
- Around line 8-11: The sidecar manifest is using the wrong container
image/entrypoint for the readiness contract; replace the current agnhost netexec
setup with the custom readiness-sidecar image used by
experiments/sidecar/main.go so the container polls /tmp/signal/ready and only
serves /healthz after it exists. Update the image and command/args in the
sidecar manifest to point at that readiness-sidecar implementation, keeping the
pod behavior aligned with measure-sidecar-readiness.sh.

In `@rfc/NNNN-warm-pool-feasibility/README.md`:
- Around line 176-189: Close the claim/create race in the warm-pool fallback
logic by adding an explicit cancellation or terminal-state check before
switching to the cold-start path. Update the timeout handling around
wait_for_claim_ready and the delete_claim/create_sandbox_cold_start flow so the
driver revalidates the SandboxClaim state after timeout and only proceeds to
create_sandbox_cold_start when the claim is confirmed not to have bound or is
safely terminated.
- Around line 281-317: The warm-pool flow in the sandbox creation path records
only Pending and then returns before persisting the new warm-claim lifecycle
state, leaving WarmClaimed unused. Update the warm path around the
create_claim/wait_claim_bound/inject_identity sequence to transition the sandbox
store into WarmClaimed once the claim is bound and before returning, so the
SandboxState enum entry is actually reachable and status/cleanup logic can
distinguish it from Pending.

---

Outside diff comments:
In `@experiments/measure-cold-start.sh`:
- Around line 148-217: The vanilla runner currently hardcodes the sandbox image
in run_vanilla_config, so the --image override and SANDBOX_IMAGE setting are
ignored for this path. Update the inline Sandbox manifest in run_vanilla_config
to reference SANDBOX_IMAGE instead of the fixed pause image, and keep the rest
of the create/wait/cleanup flow unchanged so the existing CLI option applies
consistently to vanilla runs.

---

Nitpick comments:
In `@experiments/manifests/readiness-gate-pod.yaml`:
- Around line 9-15: Add a restrictive securityContext to the sandbox container
in the readiness-gate pod manifest so the container uses a hardened default.
Update the sandbox container spec to explicitly set readOnlyRootFilesystem and
allowPrivilegeEscalation: false, and align any other default security settings
needed for this pod. Use the sandbox container block in the manifest to locate
the change.

In `@experiments/manifests/sidecar-readiness.yaml`:
- Around line 27-36: Add a securityContext to the sandbox container in the
sidecar readiness manifest, matching the readiness-gate-pod manifest’s container
hardening. Update the sandbox container definition to explicitly set the same
default security settings, including readOnlyRootFilesystem, so the experiment
pod passes static analysis and uses the intended secure runtime profile.

In `@rfc/NNNN-warm-pool-feasibility/README.md`:
- Around line 252-255: The note in the projected-volume propagation guidance
assumes sub-second annotation updates from kubelet, but the reviewer is asking
to verify the operational impact of using a 1s kubelet sync before treating that
latency as feasible. Update the section around the kubelet propagation and
polling fallback text to explicitly state that `--sync-frequency=1s` is a
cluster-wide kubelet setting, and qualify the Phase 1/2 latency goals unless
OpenShift capacity/overhead has been validated; keep the fallback polling
mention tied to the supervisor behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 06383420-8657-45a3-b9bd-9d7f8d47f939

📥 Commits

Reviewing files that changed from the base of the PR and between 709b0f8 and 64da544.

📒 Files selected for processing (14)
  • experiments/RESULTS.md
  • experiments/lib/common.sh
  • experiments/manifests/image-prepull-daemonset.yaml
  • experiments/manifests/readiness-gate-pod.yaml
  • experiments/manifests/sandbox-template.yaml
  • experiments/manifests/sidecar-readiness.yaml
  • experiments/manifests/warm-pool.yaml
  • experiments/measure-cold-start.sh
  • experiments/measure-combined.sh
  • experiments/measure-env-injection.sh
  • experiments/measure-readiness-gates.sh
  • experiments/measure-sidecar-readiness.sh
  • experiments/measure-warm-pool.sh
  • rfc/NNNN-warm-pool-feasibility/README.md
✅ Files skipped from review due to trivial changes (1)
  • experiments/RESULTS.md
🚧 Files skipped from review as they are similar to previous changes (8)
  • experiments/manifests/warm-pool.yaml
  • experiments/manifests/image-prepull-daemonset.yaml
  • experiments/measure-readiness-gates.sh
  • experiments/measure-env-injection.sh
  • experiments/measure-sidecar-readiness.sh
  • experiments/lib/common.sh
  • experiments/measure-combined.sh
  • experiments/measure-warm-pool.sh

Comment thread experiments/manifests/sidecar-readiness.yaml
Comment on lines +176 to +189
When the warm pool has zero ready replicas or the SandboxClaim stays
Pending for longer than a configurable timeout (default: 5 seconds), the
driver falls back to the current cold-start path (creating a Sandbox
resource directly).

```rust
match timeout(Duration::from_secs(5), wait_for_claim_ready(&claim)).await {
Ok(sandbox_name) => { /* warm path */ },
Err(_) => {
delete_claim(&claim).await;
create_sandbox_cold_start(&sandbox).await; // existing path
}
}
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Close the claim/create race before falling back.

Deleting the claim on timeout and immediately creating a cold sandbox can double-provision if the claim binds just after the timeout, or leave warm capacity stranded. The fallback needs an explicit cancellation/terminal-state check before switching paths.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rfc/NNNN-warm-pool-feasibility/README.md` around lines 176 - 189, Close the
claim/create race in the warm-pool fallback logic by adding an explicit
cancellation or terminal-state check before switching to the cold-start path.
Update the timeout handling around wait_for_claim_ready and the
delete_claim/create_sandbox_cold_start flow so the driver revalidates the
SandboxClaim state after timeout and only proceeds to create_sandbox_cold_start
when the claim is confirmed not to have bound or is safely terminated.

Comment on lines +281 to +317
// Store sandbox as "pending" in the sandbox store
self.store.insert_pending(sandbox_id, &request.name);

// Try warm pool first
if let Some(pool) = self.driver.find_warm_pool(&namespace).await {
match self.driver.create_claim(&request.name, &pool).await {
Ok(claim) => {
let sandbox_name = self.driver.wait_claim_bound(&claim).await?;
self.driver.inject_identity(&sandbox_name, &sandbox_id).await?;
// Supervisor will call back via ConnectSupervisor
return Ok(sandbox_id);
}
Err(_) => { /* fall through to cold start */ }
}
}

// Cold-start fallback (existing path)
self.driver.create_sandbox(&sandbox_id, &request).await
}
```

#### 3.2 Sandbox Store Changes

The sandbox store needs to track the warm pool lifecycle:

```rust
enum SandboxState {
Pending, // Created, waiting for compute
WarmClaimed, // Claim bound, waiting for supervisor activation
Connected, // Supervisor called ConnectSupervisor
Ready, // SSH available, sandbox usable
// ... existing states
}
```

The `WarmClaimed` state is new and represents the window between claim
binding and supervisor activation.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Persist the WarmClaimed transition.

The warm path inserts Pending, then returns after identity injection without ever recording the new warm-claim state. As written, the WarmClaimed state below is unreachable, and status/cleanup code will not be able to distinguish a bound warm claim from an ordinary pending sandbox.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rfc/NNNN-warm-pool-feasibility/README.md` around lines 281 - 317, The
warm-pool flow in the sandbox creation path records only Pending and then
returns before persisting the new warm-claim lifecycle state, leaving
WarmClaimed unused. Update the warm path around the
create_claim/wait_claim_bound/inject_identity sequence to transition the sandbox
store into WarmClaimed once the claim is bound and before returning, so the
SandboxState enum entry is actually reachable and status/cleanup logic can
distinguish it from Pending.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
experiments/manifests/sandbox-template.yaml (1)

15-15: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Consider pinning image digests for a reproducibility study.

All three images (sandboxes/base, agent, supervisor) use :latest. Since this template backs recorded latency results, a floating tag makes the measurements non-reproducible: a later :latest push changes image size/init time and invalidates comparisons against the archived runs. Pinning to a digest (or a fixed tag) would tie results to a known image.

Also applies to: 33-33, 89-89

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@experiments/manifests/sandbox-template.yaml` at line 15, Replace the floating
:latest tags for the base, agent, and supervisor images in the sandbox manifest
with immutable image digests or fixed version tags, keeping all three references
consistent with the versions used for the recorded latency results.
experiments/measure-warm-pool.sh (1)

313-315: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reuse get_claimed_sandbox_name here
This repeats the same jsonpath='{.status.sandbox.name}' lookup already wrapped by the helper, so using the helper keeps both call sites aligned if the field path changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@experiments/measure-warm-pool.sh` around lines 313 - 315, Replace the
duplicated kubectl lookup in the claim-sandbox polling logic with the existing
get_claimed_sandbox_name helper, passing claim_name and NAMESPACE as required;
preserve the current empty-result behavior and use the helper’s returned value
for subsequent processing.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@experiments/manifests/sandbox-template.yaml`:
- Line 15: Replace the floating :latest tags for the base, agent, and supervisor
images in the sandbox manifest with immutable image digests or fixed version
tags, keeping all three references consistent with the versions used for the
recorded latency results.

In `@experiments/measure-warm-pool.sh`:
- Around line 313-315: Replace the duplicated kubectl lookup in the
claim-sandbox polling logic with the existing get_claimed_sandbox_name helper,
passing claim_name and NAMESPACE as required; preserve the current empty-result
behavior and use the helper’s returned value for subsequent processing.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8e4a61d9-f455-4d24-a40e-95532a50bd1a

📥 Commits

Reviewing files that changed from the base of the PR and between 64da544 and 62dc8ed.

⛔ Files ignored due to path filters (8)
  • experiments/results/2026-07-09-rosa-hcp-422/cold-start-noprepull.csv is excluded by !**/*.csv
  • experiments/results/2026-07-09-rosa-hcp-422/cold-start-prepulled.csv is excluded by !**/*.csv
  • experiments/results/2026-07-09-rosa-hcp-422/cold-start-vanilla.csv is excluded by !**/*.csv
  • experiments/results/2026-07-09-rosa-hcp-422/env-injection-allowed.csv is excluded by !**/*.csv
  • experiments/results/2026-07-09-rosa-hcp-422/env-injection-disallowed.csv is excluded by !**/*.csv
  • experiments/results/2026-07-09-rosa-hcp-422/readiness-gates.csv is excluded by !**/*.csv
  • experiments/results/2026-07-09-rosa-hcp-422/warm-pool-burst.csv is excluded by !**/*.csv
  • experiments/results/2026-07-09-rosa-hcp-422/warm-pool-default.csv is excluded by !**/*.csv
📒 Files selected for processing (20)
  • experiments/RESULTS.md
  • experiments/manifests/image-prepull-daemonset.yaml
  • experiments/manifests/readiness-gate-pod.yaml
  • experiments/manifests/sandbox-template.yaml
  • experiments/manifests/sidecar-readiness.yaml
  • experiments/measure-cold-start.sh
  • experiments/measure-warm-pool.sh
  • experiments/results/.gitignore
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-1.json
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-10.json
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-2.json
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-3.json
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-4.json
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-5.json
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-6.json
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-7.json
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-8.json
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-9.json
  • experiments/results/README.md
  • rfc/NNNN-warm-pool-feasibility/README.md
✅ Files skipped from review due to trivial changes (13)
  • experiments/results/README.md
  • experiments/results/.gitignore
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-2.json
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-5.json
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-9.json
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-1.json
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-7.json
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-4.json
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-3.json
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-6.json
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-10.json
  • experiments/results/2026-07-09-rosa-hcp-422/events-wp-default-run-8.json
  • rfc/NNNN-warm-pool-feasibility/README.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • experiments/manifests/readiness-gate-pod.yaml
  • experiments/manifests/sidecar-readiness.yaml
  • experiments/measure-cold-start.sh

devin-ai-integration[bot]

This comment was marked as resolved.

rhuss added a commit that referenced this pull request Jul 10, 2026
Applied fixes from bot review comments:
- Fix CSV header mismatch in common.sh (init_ms/supervisor_ms/ssh_ms)
- Fix (( elapsed++ )) under set -e crashing on first iteration (10 occurrences)
- Fix usage() exiting 0 on error in all experiment scripts
- Surface cleanup timeouts with log warning and return 1

Assisted-By: 🤖 Claude Code
Signed-off-by: Roland Huß <rhuss@redhat.com>
rhuss added 4 commits July 11, 2026 08:37
Parent brainstorm (01) defines the layered measurement approach for
evaluating Agent Sandbox warm pooling on OpenShift. Child documents
cover cluster setup (02), measurements (03), and results synthesis (04).

Assisted-By: 🤖 Claude Code
Assisted-By: 🤖 Claude Code
Signed-off-by: Roland Huß <rhuss@redhat.com>
Assisted-By: 🤖 Claude Code
Signed-off-by: Roland Huß <rhuss@redhat.com>
Feasibility study for warm pool integration with the Agent Sandbox
operator on OpenShift (ROSA HCP 4.22). Key findings:

- Claiming a pre-provisioned pod takes ~1.4s vs 16.7s cold start (12x)
- Claim latency is image-independent (tested pause + full 3.2GB sandbox)
- Identity binding via spec.env bypasses warm pool (creates fresh pod)

Two RFCs for identity binding alternatives:
- Annotation-based (~3s latency, ~18 points)
- gRPC-push with always-on supervisor (sub-2s target, ~24 points)

Prototype brainstorm (M1: ActivateSandbox gRPC PoC, M2: SandboxProfile
entity with workspace-scoped pool lifecycle) incorporating NVIDIA
feedback on unidentified supervisor state and SandboxProfile entity.

Includes reproducible experiment scripts, measurement data, and
analysis tooling.

Assisted-By: 🤖 Claude Code
Signed-off-by: Roland Huß <rhuss@redhat.com>
@rhuss
rhuss force-pushed the 6111-warm-pool-feasibility branch from 0b70b76 to 1635442 Compare July 11, 2026 09:21

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

View 8 additional findings in Devin Review.

Open in Devin Review

burst 5 simultaneous claims to measure burst behavior and pool replenishment
all Run all configurations sequentially
EOF
exit 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Invalid command-line arguments silently succeed instead of reporting failure

The warm pool measurement script exits successfully when given unknown options (exit 0 at experiments/measure-warm-pool.sh:37), so wrapper scripts and CI pipelines that check exit codes will miss the misconfiguration.

Impact: Experiment runs with typos in flags appear to succeed, producing no measurements and no error signal.

Constitution Principle II violation: usage function unconditionally exits 0

The usage() function at experiments/measure-warm-pool.sh:37 uses exit 0 unconditionally. When called from the error path at line 49 (*) log "ERROR: Unknown option: $1"; usage ;;), the script exits with status 0 despite encountering an invalid argument.

The repository's constitution (.specify/memory/constitution.md:39-48) requires: "Usage/help functions called from error paths MUST exit with non-zero status. The recommended pattern is exit "${1:-0}" in the usage function body, with usage 0 for help requests and usage 1 for error call sites."

All five other experiment scripts in this PR correctly implement this pattern (e.g., experiments/measure-cold-start.sh:34 uses exit "${1:-0}" and line 44 calls usage 1). Only measure-warm-pool.sh deviates.

Suggested change
exit 0
exit "${1:-0}"
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

--template) TEMPLATE_NAME="$2"; shift 2 ;;
--timeout) CLAIM_TIMEOUT="$2"; shift 2 ;;
-h|--help) usage ;;
*) log "ERROR: Unknown option: $1"; usage ;;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Error path for unknown options exits successfully instead of with failure status

The error handler for unrecognized flags calls the help function without requesting a non-zero exit (usage at experiments/measure-warm-pool.sh:49), so the script reports success even when invoked with invalid arguments.

Impact: Automated experiment harnesses cannot detect misconfigured measurement runs.

Constitution Principle II violation: error call site does not pass non-zero exit code

At experiments/measure-warm-pool.sh:49, the unknown-option handler calls usage without an argument. Even after fixing BUG-0001 to use exit "${1:-0}", calling usage without an argument defaults to exit 0. The error call site must pass 1 to signal failure, matching the pattern used in all other experiment scripts (e.g., experiments/measure-cold-start.sh:44: usage 1).

Suggested change
*) log "ERROR: Unknown option: $1"; usage ;;
*) log "ERROR: Unknown option: $1"; usage 1 ;;
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@rhuss

rhuss commented Jul 11, 2026

Copy link
Copy Markdown
Owner Author

@copilot resolve the merge conflicts in this pull request

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

View 9 additional findings in Devin Review.

Open in Devin Review

Comment on lines +96 to +100
<<<<<<< HEAD
uses: astral-sh/setup-uv@f98e06938123ccabd21905ea5d0069192241f9f1 # v8.3.1
=======
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
>>>>>>> origin/main

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Unresolved merge conflict markers break the CI workflow file

Unresolved git merge conflict markers are left in the workflow file (<<<<<<< HEAD at .github/workflows/sync-docs.yml:96), so GitHub Actions will fail to parse the YAML and the sync-docs workflow will not run.

Impact: The documentation sync workflow is broken and will error on every trigger.

Merge conflict markers in YAML

Lines 96-100 contain literal <<<<<<< HEAD, =======, and >>>>>>> origin/main markers between two different setup-uv action SHA references. YAML parsers treat these as invalid syntax, causing the entire workflow to fail before any step executes.

<<<<<<< HEAD
        uses: astral-sh/setup-uv@f98e06938123ccabd21905ea5d0069192241f9f1 # v8.3.1
=======
        uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
>>>>>>> origin/main
Suggested change
<<<<<<< HEAD
uses: astral-sh/setup-uv@f98e06938123ccabd21905ea5d0069192241f9f1 # v8.3.1
=======
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
>>>>>>> origin/main
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread brainstorm/00-overview.md
Comment on lines +3 to +7
<<<<<<< HEAD
Last updated: 2026-07-11
=======
Last updated: 2026-07-10
>>>>>>> origin/main

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Unresolved merge conflict markers in brainstorm overview document

Unresolved git merge conflict markers are left throughout the brainstorm overview (<<<<<<< HEAD at brainstorm/00-overview.md:3), so the document renders with raw conflict syntax instead of coherent content.

Impact: The brainstorm overview is unreadable, showing duplicate conflicting sections with git markers.

Multiple conflict blocks in the file

The file contains conflict markers at lines 3-7, 17-23, 33-42, 51-62. Each block has both HEAD and origin/main versions of the content left unresolved. For example, the sessions table has two different sets of entries (sessions 05-07 from HEAD vs session 05 from origin/main).

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants