cellos-host-stub 0.5.1

Stub backend for CellOS — in-process test double for the CellBackend trait. Use in CI / dev when you don't want to boot a real VM.
Documentation
# 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

| Item | Where |
|---|---|
| `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:

| Mechanism | Value |
|---|---|
| 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/`):

| File | Scope |
|---|---|
| `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".