Skip to content

PRISM Compute Plane: miner-funded GPU worker plane (base)#37

Draft
echobt wants to merge 11 commits into
mainfrom
mission/compute-plane
Draft

PRISM Compute Plane: miner-funded GPU worker plane (base)#37
echobt wants to merge 11 commits into
mainfrom
mission/compute-plane

Conversation

@echobt

@echobt echobt commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Mission branch for the PRISM Compute Plane (base repo). Delivered incrementally per milestone; this PR aggregates the mission work on `mission/compute-plane`.

M1 providers (in progress)

compute-provider-contract-and-lium-client

  • `src/base/compute/provider.py`: `ProviderClient` protocol, `InstanceSpec` (mandatory `max_lifetime_hours`/`max_price_per_hour` cost-guardrail bounds), `Offer`/`Instance`, typed `ProviderError`/`CostGuardrailError`.
  • `src/base/compute/lium.py`: `LiumClient` over httpx (`X-API-Key`, base `https://lium.io/api\`):
    • `list_offers` with per-GPU price filtering
    • `provision` refuses unbounded/over-priced specs before any network call, always sends a bounded `termination_hours`, and terminates+verifies the pod on any post-rent failure (try/finally)
    • idempotent `ensure_ssh_key` / `ensure_template`; idempotent `terminate`; `verify_terminated` via `GET /pods`
    • `stream_logs`, `watchtower_digest`, `GET /users/me` balance
    • API key never logged, repr'd, or embedded in errors
  • 50 offline respx unit tests (VAL-PROV-001/003/004/005/011/017/018 + secret hygiene).

All new behavior is additive (new package); no existing behavior changed. Full base gate green: ruff, format, mypy, and pytest (1316 passed, coverage 89.1%).

Add src/base/compute/ package:
- provider.py: ProviderClient protocol, InstanceSpec (mandatory
  max_lifetime_hours/max_price_per_hour bounds), Offer/Instance, typed
  ProviderError/CostGuardrailError.
- lium.py: LiumClient over httpx (X-API-Key, base https://lium.io/api).
  list_offers price filtering; provision refuses unbounded/over-priced
  specs before any network call, always sends bounded termination_hours,
  and terminates+verifies on any post-rent failure (try/finally);
  idempotent ensure_ssh_key/ensure_template; idempotent terminate;
  verify_terminated via GET /pods; stream_logs; watchtower digest;
  GET /users/me balance. API key never logged/repr'd/in errors.

50 offline respx unit tests (VAL-PROV-001/003/004/005/011/017/018 +
secret hygiene). Full base gate green: 1316 passed, coverage 89.1%.
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 91673409-7829-465a-878d-3c5950f9d744

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mission/compute-plane

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.

echobt added 10 commits July 6, 2026 17:30
Add build_lium_worker_template (Lium CustomTemplateRequest payload) and
build_targon_worker_app (Targon app definition) in src/base/compute/
worker_deployment.py. Both pin the docker image BY DIGEST via a shared
pinned_image_reference helper; the image+digest default to the published
prism-evaluator digest (M1 placeholder) and are inputs so M2 swaps in
docker/Dockerfile.worker with a one-line change.

Well-formedness is enforced (required fields, internal ports incl. 22, env
plumbing, is_private, no embedded secrets) and covered by offline respx tests
that also assert the whole compute suite makes zero real network calls under
respx strict mode and needs no provider credentials (VAL-PROV-009/010/016).
…TESTS

Add scripts/live_lium_e2e.py driving the M1 provider clients against
production: read-only reachability (Lium users/me + executors +
watchtower/digest, Targon inventory + apps) plus one batched Lium rental
cycle (ensure ssh key + template -> rent cheapest suitable executor ->
poll RUNNING -> ssh nvidia-smi -> logs -> DELETE -> verify gone -> record
balance delta). Pod is deleted in a finally on every path; opt-in via
BASE_LIVE_PROVIDER_TESTS=1 so the default suite stays offline.
…gpu shape

- LiumClient.provision rejects sub-1-hour max_lifetime_hours so
  termination_hours never truncates to 0 (auto-termination stays on)
- widen post-rent cleanup guard to key off rent success, not pod-id
  resolution: a transient GET /pods failure during resolution still
  best-effort terminates + verifies the just-rented pod
- normalize Targon Offer.price_per_hour to per-GPU (cost_per_hour / gpu_count)
  so the per-GPU max_price cap filters multi-GPU shapes correctly
- default WORKER_GPU_SHAPE 'h100' -> live-valid 'h100-small'
Add the miner-funded GPU worker plane registry (architecture.md sec 3.3),
gated behind compute.worker_plane_enabled:

- alembic 0009: worker_registrations + worker_faults + worker_request_nonces
  on the existing chain (0008 -> 0009), no legacy table altered.
- WorkerCoordinationService mirroring validator_coordination patterns:
  POST /v1/workers/register (sr25519 miner binding verified against the mock
  metagraph, binding-nonce replay protection, no silent cross-owner rebind),
  POST /v1/workers/{id}/heartbeat, GET /v1/workers (fleet: status/owner/
  provider/last-seen/faults, authenticated-but-not-admin), and
  GET /v1/workers/active?hotkey= (admission surface).
- Lifecycle pending -> active -> stale -> retired with
  compute.worker_heartbeat_ttl_seconds (default 120); retired is terminal
  (no heartbeat resurrection); staleness derived on read + a background pass.
- worker_auth: binding message/verify, signed-request verifier + registered-
  worker/validator eligibility, worker nonce store.
- Wired into create_proxy_app + the master proxy CLI (flag-off => unmounted).

Unit + Postgres integration tests (15433) cover VAL-MASTER-001/002/015/016/
018/021 and VAL-AGENT-015.
Add the miner-funded WorkerAgent (src/base/worker/): register under a
miner-signed binding, heartbeat to stay active, pull gpu-only replicas,
execute via the AssignmentExecutor seam on its local broker, and post
results that always carry an ExecutionProof envelope (sr25519 over
sha256('{manifest_sha256}:{unit_id}'), pinned identically to prism).

Extract the shared agent-loop primitives into base/coordination/agent_loop
(BackoffPolicy, is_transient_error, AgentCycleSummary, sleep_until,
backoff_sleep); the validator agent now imports them with behavior unchanged.

Add the master worker assignment plane (worker_assignments table + 0010
migration, worker-authenticated pull/result routes gated on registration
and liveness, never a validator permit) and wire it behind
compute.worker_plane_enabled.

Fulfills VAL-AGENT-002/003/004/005/006/007/008/016/017/018.
Add a top-level `base worker` Typer app distinct from the legacy
`base master worker` Swarm group:

- deploy --provider local starts a miner-funded agent against a local
  master and reports it active within 60s.
- deploy --provider lium|targon requires the provider key env (actionable
  refusal before any network), bounds offer selection by --max-price
  preferring an exact gpu_count executor (next-cheapest fallback), and
  never transmits the provider key to the master (pod env excludes it).
- status renders the fleet from GET /v1/workers (signed as the worker key).

Thread startup_commands through InstanceSpec, LiumClient.ensure_template
and build_lium_worker_template (validated metachar-free) per the
live-learned Lium rent constraint; keep docker/Dockerfile.worker's
exec-form entrypoint metachar-free.

Add WorkerSettings, worker/miner keypair resolvers, signed list_workers,
config/worker.example.yaml, and unit tests. All behind
compute.worker_plane_enabled; full base gate green.
Add WorkerAssignmentEngine that materializes gpu work-unit replicas onto
ACTIVE distinct-owner workers behind compute.worker_plane_enabled: R=2 with
self-evaluation exclusion (unit waits under sole-capacity scarcity), graceful
degradation to R=1 with a recorded warning, per-worker gpu concurrency 1, and
per-replica deadline/reassignment bounded by max_attempts. The validator
AssignmentService skips worker-plane capabilities when the flag is on, so
flag-OFF gpu routing to validators stays byte-identical to legacy.
… behind flag

Reconcile replicated gpu worker results (architecture.md 3.3): matching
ExecutionProof.manifest_sha256 forwards exactly one result to the challenge;
divergent hashes dispute the unit (never forwarded, before or after audit) and
create a validator-executor audit unit whose outcome writes worker_faults for
the divergent worker(s), visible in fleet status. Single-replica reporting
terminates deterministically (accept-after-degrade with warning); late/foreign
posts stay rejected with replica state intact. All gated by
compute.worker_plane_enabled (reconciler is None when off).
Legacy AssignmentService.reclaim_stale_assignments treated a null
assigned_validator_hotkey as 'offline validator => reassignable', so under
the worker plane a worker-owned prism PRIMARY (ASSIGNED, null hotkey by
design) churned back to PENDING every MasterOrchestrationDriver.run_once
pass. _assign_pending_in_session already skipped such units via
worker_plane_capabilities; _reclaim_in_session did not. Factor the guard
into AssignmentService._worker_plane_owns and apply it in BOTH paths so a
worker-owned primary is neither assigned nor reclaimed here, while a
genuinely stale validator unit (cpu, or gpu AUDIT with executor_kind=
validator) is still reclaimed. Flag OFF keeps reclaim byte-identical to
legacy.
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