shipper-core 0.3.0-rc.2

Core library behind the `shipper` CLI: engine, planning, state, registry, and remediation primitives for `cargo publish` workspaces.
Documentation
# Layer: `ops` (I/O primitives)

**Position in the architecture:** Layer 1 (bottom). The lowest layer of the `shipper` crate.

## Single responsibility

Talk to the outside world: filesystem, git binary, cargo subprocess, OS, network.

## Import rules

`ops` modules MUST NOT import from any higher layer:
- `use crate::engine::...`
-`use crate::plan::...`
-`use crate::state::...`
-`use crate::runtime::...`

`ops` modules MAY import from:
- `crate::types` (re-exports of `shipper-types`)
- ✅ External crates (`anyhow`, `serde`, `tokio`, etc.)
- ✅ Other `crate::ops::*` modules (with care — prefer `mod.rs` facades over deep paths)

These are enforced by `.github/workflows/architecture-guard.yml`.

## What lives here

Each absorbed I/O microcrate gets its own folder under `ops/`:

- `ops/auth/` — Cargo registry token resolution (was `shipper-auth`)
- `ops/git/` — Git cleanliness checks, context capture (was `shipper-git`)
- `ops/lock/` — Advisory file lock (was `shipper-lock`)
- `ops/process/` — Cross-platform command execution (was `shipper-process`)
- `ops/cargo/` — Cargo metadata + cargo publish invocation (was `shipper-cargo`)
- `ops/storage/` — Storage backend trait + filesystem impl (was `shipper-storage`)

## What does NOT live here

- `shipper-registry`, `shipper-webhook`, `shipper-sparse-index` — these are public crates that `shipper` depends on directly. No internal wrapper inside `ops/`.
- Domain types — those live in `shipper-types`.
- Orchestration — that's `engine/`.

## Boundary discipline

- Each subfolder has its own `mod.rs` facade. Other modules talk through the facade, not by reaching into deep paths.
- Default visibility: `pub(crate)`. Only items truly part of `shipper`'s public API get `pub`.
- Each subfolder has its own `CLAUDE.md` describing its single responsibility.