# cellos-host-stub
The minimal, no-op [`CellBackend`] used wherever the supervisor pipeline
must run but no real isolation is desired.
## What it is
`cellos-host-stub` provides exactly one type — [`StubCellBackend`] — that
implements [`cellos_core::ports::CellBackend`] with no syscalls, no
subprocesses, no namespaces, no cgroups, and no network state. `create()`
returns a `CellHandle` for the spec it was given (after a single
`spec.id` non-empty check); `destroy()` returns a successful
`TeardownReport` with `destroyed: true` and `peers_tracked_after: 0`.
The crate is part of L2 in the [layer model](../../LAYERS.md) — host
runtime / isolation — but it deliberately does **none** of the isolation
work that L2 normally owns. Its only purpose is to let the L3 supervisor
exercise its full create → run → destroy state machine in unit tests
without booting a microVM, creating a network namespace, or touching the
host's cgroup tree. The supervisor's composition root selects it when
`CELLOS_CELL_BACKEND=stub` (see
`crates/cellos-supervisor/src/composition.rs:1081`).
It is not a production backend. It cannot enforce egress, cannot apply
nftables rules, does not own a cgroup leaf, does not stamp any artifact
digests on the returned handle, and never spawns the cell's `argv`. The
supervisor's host-subprocess fallback (`run_cell_command`) is what
actually executes the workload when this backend is in play.
## Public API surface
| `pub struct StubCellBackend` | `src/lib.rs:10` |
| `impl CellBackend for StubCellBackend` | `src/lib.rs:13` |
| `async fn create(&self, &ExecutionCellDocument) -> Result<CellHandle, CellosError>` | `src/lib.rs:15` |
| `async fn destroy(&self, &CellHandle) -> Result<TeardownReport, CellosError>` | `src/lib.rs:33` |
`create()` returns a `CellHandle` with `cgroup_path`, `nft_rules_applied`,
`kernel_digest_sha256`, `rootfs_digest_sha256`, and
`firecracker_digest_sha256` all set to `None` — the stub backend has no
boot artifact manifest and does not own enforcement state (`src/lib.rs:19-29`).
The only failure mode at `create()` is an empty `spec.id`, which is
rejected with `CellosError::InvalidSpec("spec.id must be non-empty")`
(`src/lib.rs:16-18`).
## Architecture / how it works
There is no state. `StubCellBackend` is a unit struct
(`pub struct StubCellBackend;` at `src/lib.rs:10`); each `create()` /
`destroy()` call validates its inputs and returns an `Ok(...)` value
with no side effects. Both methods are `#[instrument]`-traced so the
supervisor's `tracing` spans still show stub create/destroy crossings.
`destroy()` always reports `peers_tracked_after: 0` — there are no
"peers" because the stub tracks nothing across calls.
## Configuration
None. The backend has no environment variables, no config struct, and
no feature flags. Selection happens one level up, in the supervisor:
| Supervisor selection env var | `CELLOS_CELL_BACKEND=stub` |
| Selected at | `crates/cellos-supervisor/src/composition.rs:1081` |
## Examples
```rust
use std::sync::Arc;
use cellos_core::ports::CellBackend;
use cellos_host_stub::StubCellBackend;
let backend: Arc<dyn CellBackend> = Arc::new(StubCellBackend);
// The supervisor drives the rest — create() / destroy() are awaited
// through the trait object during cell lifecycle management.
```
The supervisor's own composition path is:
```rust
// crates/cellos-supervisor/src/composition.rs:1081
"stub" => Arc::new(StubCellBackend),
```
## Testing
```
cargo test -p cellos-host-stub
```
Three test files exercise the backend (`tests/`):
| `smoke.rs` | Construction + basic create/destroy. |
| `cellos_host_stub_happy_path.rs` | End-to-end happy path through the trait. |
| `contract.rs` | HSTUB-COV — pins the observable contract against `CellBackend` so the stub does not drift from the Firecracker / proprietary backends. |
None of these require Linux, KVM, root, or any host syscalls. They run
on every CI leg, including macOS and Windows targets.
## Related crates
- [`cellos-core`](../cellos-core) — defines the `CellBackend` trait the
stub implements.
- [`cellos-host-cellos`](../cellos-host-cellos) — the default
proprietary backend the supervisor falls back to when
`CELLOS_CELL_BACKEND` is unset.
- [`cellos-host-firecracker`](../cellos-host-firecracker) — the
microVM-backed production backend the stub stands in for in tests.
- [`cellos-host-gvisor`](../cellos-host-gvisor) — `runsc`-backed
alternative for hosts without KVM.
- [`cellos-supervisor`](../cellos-supervisor) — selects the backend at
startup via `CELLOS_CELL_BACKEND`.
## ADRs
- [ADR-0001 — Rust + NATS/JetStream + proprietary host](../../docs/adr/0001-rust-nats-jetstream-proprietary-host.md)
— the surrounding architectural commitments that make a no-op stub
acceptable in lieu of "use the real backend in tests".