Skip to content

plugin-preempt

Version 2026.183.0000
Repo superproject
Plugin yes — see the plugin reference

COMPILED-IN charly plugin owning the RESOURCE ARBITER (cutover C9) — the final core-externalization cutover. It serves TWO capabilities:

  • verb:arbiter — the exclusive/shared resource arbiter, the 1225-LOC coordination logic MOVED OUT of charly core (the former charly/preempt.go ResourceArbiter): acquire/release exclusive+shared leases, stop + restore preemptible holders, the crash-safe lease ledger (~/.local/share/charly/preemption/leases.yml), GPU-resource poisoning (device_lock-wedge containment), owner liveness, and the vfio<->nvidia driver-mode arbitration math (arbiter.go + arbiter_support.go). The arbiter reaches its HOST dependencies — the project config, the VM/pod lifecycle, the GPU driver flip — that it cannot hold across the module boundary over TWO generic reverse legs: gather/resources read the generic Executor.InvokeProvider(“build”,“project”) envelope (K1-unblock wave 1 — the former bespoke arbiter reverse-RPC channel

    • its host handler are DELETED); the other 6 (running / stop[+wait] / start / switchMode / ensureCDI / gpuCDI) run over Executor.InvokeProvider (FLOOR-SLIM-proper Unit-8, holder_dispatch.go — a prior cutover). The in-core PROXY (charly/preempt.go newResourceArbiter + acquire*/release* shims) is the generic core→verb registry bridge the core LEASE-LIFECYCLE consumers (check-bed runner, start, vm, commands, vm_gpu_cmd) compile through, invisible above the shim (R3).
  • command:preempt — the operator charly preempt status/restore CLI. It OWNS the CLI grammar + the lease-table formatting and reaches its OWN peer capability verb:arbiter DIRECTLY via InvokeProvider over the in-proc reverse channel (no hidden __preempt-* forward, no in-core proxy hop). No ad-hoc podman/virsh (R4).

PLACEMENT — COMPILED-IN (listed in the embedded charly/charly.yml compiled_plugins:). The arbiter is on the deploy / vm-create / check-bed hot paths and needs the LOCAL lease ledger + the LOCAL project config, so in-proc is the right placement (like candy/plugin-gpu); the reverse channel is in-proc (no gRPC broker), the SAME dispatchBuild pattern. The cmd/serve binary backs the out-of-process placement.

The DRIVER-SWITCH (vfio<->nvidia rebind) that the arbiter’s switchMode seam drives now lives in candy/plugin-gpu (C9, 1B); the host receives the arbiter’s switchMode call and routes it there via the core gpu shims (a plugin->plugin edge through the host).

R10: the disposable check-preempt-arbiter-pod bed exercises the FULL acquire/preempt path with ZERO GPU — a preemptible pod holder on a SYNTHETIC selector-less token (test-lock) + a requires_exclusive claimant, so AcquireExclusive -> holdersToStop -> stopHolders+wait -> lease persisted -> applyMode SKIPS (no gpu selector) -> claim, then teardown -> ReleaseClaimant -> restoreHolders, all THROUGH the externalized dispatch + the resolved-project envelope (gather/resources) + InvokeProvider (the rest).

This candy’s plan: — the runnable spec charly check executes against a live deployment. check: steps are idempotent probes; run: steps change state.

Intent Step
check the resource-arbiter plugin ships a buildable Go module the host compiles in; the full arbiter acquire/preempt/release dispatch + the charly preempt CLI are exercised by the live R10 (check-preempt-arbiter-pod) + the Go e2e