Skip to content

feat(phase3b3): GCP worker fleet — GcsStateStore + CloudRunLauncher#22

Open
dcvz wants to merge 12 commits into
mainfrom
feat/phase3b3-gcp-worker-fleet
Open

feat(phase3b3): GCP worker fleet — GcsStateStore + CloudRunLauncher#22
dcvz wants to merge 12 commits into
mainfrom
feat/phase3b3-gcp-worker-fleet

Conversation

@dcvz

@dcvz dcvz commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

Phase 3b-3 of the distributed deployment: makes the cica worker fleet run on GCP as a self-contained second deployment, mirroring the existing AWS pair behind the unchanged StateStore/Launcher traits. cica-side primitives only — the GCP IaC is a separate track.

  • GcsStateStore (feature gcs, src/sandbox/state/gcs.rs) — GCS-backed StateStore over the official google-cloud-storage SDK. Same <prefix>/<key>/<rel> key scheme, replace semantics, and .. traversal guard as S3StateStore; ADC auth; automatic resumable uploads (no hand-rolled multipart). Uses both Storage (bytes) and StorageControl (list/delete) clients.
  • CloudRunLauncher + GcpRunClient (feature cloudrun, src/sandbox/cloudrun.rs) — runs a worker turn as a one-shot Cloud Run Job execution via google-cloud-run-v2. AWS calls sit behind a 3-method CloudRunClient trait so the launch→poll→timeout→best-effort-cancel state machine is fake-tested. RunJob returns the execution name from the poller's first poll without awaiting the LRO, then we poll GetExecution on our own cadence (symmetric with FargateLauncher).
  • Config / env / wiringStoreKind::Gcs + ProviderKind::CloudRun; GcsConfig (no region — GCS is globally addressed) and CloudRunConfig (no networking fields — Cloud Run pins VPC/egress on the Job resource; RunJob has no per-run network knob). Env overlay CICA_STORE=gcs / CICA_GCS_BUCKET. prep_skill_deps_locally treats CloudRun as a remote worker.
  • One image, both cloudscloud = ["fargate", "cloudrun"]; release.yml already builds --features cloud, so the published worker image now carries AWS + GCP with no image change (entrypoint is already cica). New CI cloud-features lane lints + unit-tests the GCP features.

Notable decision

The live GcsStateStore integration test runs against real GCS, deferred to the deploy/IaC track — exactly like Fargate's first real RunTask. fake-gcs-server was infeasible (it's REST-only; the SDK's list/delete control-plane is gRPC-only) and storage-testbench's gRPC-in-Docker was too flaky for CI. The IT code is written and auto-skips without CICA_GCS_IT.

Two behaviors are only confirmable against live GCP (inherent, deferred): RunJob's first poll carrying the execution name, and the count-based success decision against real executions.

Test plan

  • cargo test (default) — 105 passing; cargo test --features cloud — 128 passing
  • cargo clippy --all-targets -- -D warnings and --features cloud — clean
  • cargo fmt -- --check — clean
  • Default build stays lean — no GCP/AWS deps leak unguarded (cargo tree verified)
  • Live GCS round-trip + real RunJob — on the GCP-IaC/deploy track (real ADC + bucket + Cloud Run Job)

Spec: docs/superpowers/specs/2026-06-09-phase3b3-gcp-worker-fleet-design.md · Plan: docs/superpowers/plans/2026-06-09-phase3b3-gcp-worker-fleet.md

🤖 Generated with Claude Code

dcvz and others added 12 commits June 9, 2026 11:40
…cher)

Mirror of the AWS pair behind the existing StateStore/Launcher traits,
using the official google-cloud-storage + google-cloud-run-v2 SDKs.
cica-side primitives only; the GCP IaC is a separate track.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add StoreKind::Gcs and ProviderKind::CloudRun enum variants, plus
GcsConfig and CloudRunConfig structs wired into DeploymentConfig.
Feature stubs (gcs, cloudrun) added to Cargo.toml; match arms in
sandbox dispatch forward to feature-gated modules (Tasks 4/6).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mirrors S3StateStore over GCS objects (identical <prefix>/<key>/<rel> key
scheme). Uses google-cloud-storage's Storage (read/write bytes) +
StorageControl (list/delete) clients, built lazily so default_store stays
sync and network-free. Resumable uploads are automatic — no manual multipart.

When an endpoint override is set (emulator/testing) the clients use anonymous
credentials (google-cloud-auth, default-features off to dodge the aws-lc-rs
^1.17 vs rustls-locked 1.15 conflict); real GCS keeps ADC.

The gated IT (CICA_GCS_IT) auto-skips without the env. NOTE: StorageControl
is gRPC-only and fake-gcs-server serves HTTP/JSON only, so the emulator can't
exercise list/delete — the IT is correct for real GCS; CI (Task 5) must use a
real bucket, not fake-gcs-server.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…REST-only, SDK control-plane is gRPC)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds the SDK-agnostic Cloud Run launcher: CloudRunClient trait, RunJobRequest/ExecutionStatus
types, CloudRunLauncher with launch/poll/cancel state machine, and 5 fake-driven unit tests.
GcpRunClient is a temporary stub (Task 7 replaces it). Default build is unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaces the "not yet implemented" placeholder with the real feature-gated
arm (mirrors Fargate): requires a store + [deployment.cloudrun] section when
built with --features cloudrun, errors with a clear message otherwise.
Adds cloudrun_provider_requires_feature and cloudrun_provider_requires_a_store
tests; removes all #[allow(dead_code)] from cloudrun.rs now that the launcher
is constructed in production code.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extend the `cloud` umbrella feature to include both `fargate` (AWS) and
`cloudrun` (GCP), so release binaries tagged `-cloud` carry both clouds
automatically. Add a `cloud-features` CI job that lints gcs/cloudrun/cloud
and runs the full unit-test suite (gated GCS IT auto-skips without
CICA_GCS_IT). Also apply `cargo fmt` fixes in cloudrun.rs and sandbox/mod.rs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extract the inline task-count predicate in GcpRunClient::get_execution
into a pure free function `execution_succeeded` and cover all boundary
cases with a unit test, so the decision has coverage without live GCP.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

1 participant