# Consumer contract
```rust
#[derive(Clone)]
pub struct WebPodmanConfig {
pub podman: PathBuf, pub image: String, pub checker: PathBuf, pub chromium: PathBuf,
pub chromium_version: String, pub cpu_millis: u32, pub memory_bytes: u64, pub pids_limit: u32,
pub tmpfs_bytes: u64, pub shm_bytes: u64,
pub checker_timeout: Duration, pub wall_timeout: Duration,
}
pub struct CheckInput {
pub candidate: WebIdInput, pub candidate_root: PathBuf, pub projection_root: PathBuf,
pub entry: String, pub tests: String, pub selections: Vec<SelectionInput>,
}
pub struct CommandDiagnostics { pub status: ExitStatus, pub stdout: Vec<u8>, pub stderr: Vec<u8> }
pub struct CheckOutput { pub diagnostics: CommandDiagnostics, pub report: Report }
pub enum WebPodmanError {
InvalidInput { field: &'static str, reason: String }, Spawn(io::Error), Process(String),
Timeout { diagnostics: CommandDiagnostics, kill_failure: Option<String> },
Infrastructure { diagnostics: CommandDiagnostics, report: Option<Box<Report>>, reason: String },
}
pub fn WebPodman::new(config: WebPodmanConfig) -> Result<WebPodman, WebPodmanError>;
pub fn WebPodman::checker_digest(&self) -> &str; pub fn WebPodman::image_identity(&self) -> &str;
pub fn WebPodman::image_digest(&self) -> &str; pub fn WebPodman::chromium_version(&self) -> &str;
pub fn WebPodman::command_policy_identity(&self) -> &str; pub fn WebPodman::frozen_command_policy_identity(&self) -> &str;
pub fn WebPodman::check(&self, input: CheckInput) -> Result<CheckOutput, WebPodmanError>; pub fn WebPodman::check_frozen(&self, input: CheckInput, public_projection_root: impl AsRef<Path>) -> Result<CheckOutput, WebPodmanError>;
```
`WebPodmanConfig` implements `Clone`; cloning copies every field and performs no validation or I/O.
This concrete synchronous leaf runs one K1 Web check in one fresh rootless Podman container and owns no retry, cache, publication, access decision, image build or pull, browser behavior, durable state, or network work beyond the local Podman process. `CommandDiagnostics` and `WebPodmanError` implement `Debug`; `WebPodmanError` also implements `Display` and `Error`. Configuration requires canonical absolute nonsymlink executable files, an exact image reference ending in `@sha256:` and 64 lowercase hexadecimal digits, a normalized absolute in-image Chromium path, nonempty claimed Chromium version, nonzero explicit resources, and exact millisecond timeouts with wall time greater than checker time. Input roots must be canonical absolute nonsymlink directories and must not overlap each other or the checker file.
Each check rehashes the checker and rejects changed bytes. Receipt accessors return its `sha256:` digest, exact image identity and digest, claimed Chromium version, and `sha256:` identities over each mode's versioned fixed security, mount semantics and destinations, resource, timeout, and container-path policy. `check` retains the 0.1.0 behavior: `input.projection_root` is mounted and routed at `/k1/input/public`. `check_frozen` treats it as the frozen admitted view, mounts and routes it at `/k1/input/admitted`, and separately mounts the complete live `public_projection_root` at `/k1/input/public` without routing the checker or browser through that live root. Its candidate, admitted, public, and exact checker host paths must be pairwise nonoverlapping.
A valid call starts one `podman --remote=false run` with no retry. The container is removed, offline, read-only, caller-mapped, capability-free, no-new-privileges, resource-limited, and receives only read-only candidate, mode-specific projection, and checker mounts plus explicitly sized `/tmp` and shared-memory filesystems. Complete output and status are retained; timeout kills and reaps the process group. A canonical report is accepted only for exit 0 with success or exit 1 with completed failure; every other status, schema, encoding, or outcome combination is infrastructure failure.
`new` is unbenchmarked and linear in checker bytes. Identity accessors are unbenchmarked constant-time borrows. Both check modes are unbenchmarked; host work is linear in checker, request, and complete diagnostic bytes, memory retains complete diagnostics, and elapsed execution uses the explicit wall timeout followed only by process-group kill, reap, and pipe closure.