Operator Migration Guide — Python → Rust PhyCloud¶
This guide describes the cutover from the historical Python PhyCloud MVP to the canonical Rust PhyCloud service (PhyCloud/rust/). The cutover was completed in PhyWare issue #218, the final step of the Python → Rust migration epic #201, and the legacy Python source tree was removed in #269 one release cycle later.
If you are still running the Python service, the steps below describe a drain → switch → verify rollout to the Rust binary.
Compatibility at a glance¶
| Surface | Compatibility |
|---|---|
| Public HTTP API (paths, headers, response shapes) | Byte-compatible — clients (PhyTrace SDK, phyware CLI, admin dashboard, PhyComp) need no changes |
| Provenance hash chain (SHA-256 + canonical JSON) | Bit-identical — verified by replay-style compat tests in PhyCloud/rust/tests/provenance_compat.rs |
phyc_… API key format | Identical |
PHYCLOUD_* environment variables | Mostly identical (see variable mapping below) |
| Database schema | Compatible — Rust ships sqlx migrate files that are equivalent to the historical Alembic head; you can either point the Rust service at the existing database or rebuild from scratch |
| Database URL scheme | postgres://… (no +asyncpg driver suffix) for the Rust service |
| Migration tool | sqlx migrate (auto-run at startup when PHYCLOUD_AUTO_MIGRATE=true) replaces alembic upgrade head |
Cutover plan¶
1. Pre-flight¶
- Snapshot your PhyCloud database (PostgreSQL:
pg_dump). - Note any custom values for
PHYCLOUD_*environment variables in your deployment so they can be replayed against the Rust service. - Pin the Rust container image tag (or the
phywarerepo commit SHA) you intend to roll forward to.
2. Verify against the Rust service in staging¶
The repo-root docker-compose.yml builds the canonical phycloud service from the Rust Dockerfile:
Verify your existing PhyTrace SDK clients, phyware CLI scripts, and (if deployed) PhyComp instances can ingest and query against the Rust service unchanged. The built-in integration tests already run against the Rust service — see tests/integration/test_phytrace_sdk_rust_integration.py and tests/integration/test_phycomp_rust_phycloud_rust_smoke.py.
3. Switch production traffic¶
For a Kubernetes / Compose deployment the change is a one-line image swap — the Rust service listens on the same port (8000) and serves the same API surface:
For bespoke deployments built from source: change the dockerfile: field in your Compose / Helm chart to ./PhyCloud/rust/Dockerfile (built from the repo root) and rebuild.
4. Run database migrations¶
The Rust service can run sqlx::migrate!() at startup:
This replaces the standalone phycloud-migrate (Alembic) job that the historical Python service required. If you prefer to apply migrations out-of-band, run sqlx migrate run --source PhyCloud/rust/migrations against your database URL before starting the service.
The schema is forward-compatible with the historical Alembic head — no data re-keying is required.
5. Verify¶
After cutover, exercise the standard smoke checks against the new service:
# Health
curl -sf http://phycloud.example.com/health
# Bootstrap status (should report `bootstrapped: true` after first call)
curl -sf http://phycloud.example.com/bootstrap/status
# Ingest + query round-trip via the phyware CLI
phyware cloud bootstrap --endpoint https://phycloud.example.com
phyware cloud events list --limit 5
The PhyComp service (whether on Python or Rust) requires no configuration change — its PHYCOMP_PHYCLOUD_URL continues to point at the same hostname.
6. Decommission the Python service¶
Once you are satisfied the Rust service is stable:
- Remove any explicit
phycloud-pythondeployments from your Compose / Helm manifests. - Stop building from the historical Python Dockerfile in your downstream pipelines (the upstream source tree was removed in #269).
Environment variable mapping¶
Most PHYCLOUD_* variables are accepted unchanged. Exceptions worth calling out:
| Variable | Python (historical) | Rust (canonical) | Notes |
|---|---|---|---|
PHYCLOUD_DATABASE_URL | postgresql+asyncpg://… | postgres://… | Drop the +asyncpg driver suffix; sqlx uses the bare scheme. |
PHYCLOUD_AUTO_MIGRATE | n/a | true / false | New flag; tells the Rust binary to run sqlx::migrate!() at startup. |
PHYCLOUD_CORS_ORIGINS | JSON list (e.g. '["http://…"]') | currently a no-op | The Rust service does not yet honour this variable; CORS is open in dev mode (PHYWARE_DEV_MODE=1) and disabled in production. Track future work in the migration epic. |
PHYCLOUD_LOG_JSON | derived from structlog config | true / false | Default true; emits structured JSON identical in shape to the historical structlog output. |
PHYCLOUD_JWT_SECRET / PHYCLOUD_LICENSE_SECRET | required in prod | required in prod | Unchanged. |
PHYCLOUD_RATE_LIMIT_* | required for slowapi | required for tower-governor | Unchanged grammar (<count>/<period>). |
A full list of supported variables is documented in PhyCloud/rust/src/settings.rs and the crate README.md.
Getting help¶
- File issues against the PhyWare repository.
- The canonical service README lives at
PhyCloud/rust/README.md. - The cutover tracking issue is #218.