# observer-rust
`observer-rust` is the low-level Rust runtime surface for defining Observer-compatible test registries.
It is intentionally small. This crate does not provide macros or a human-first authoring DSL. Instead, it exposes the deterministic registration and execution types that higher-level Rust integrations build on.
## What It Provides
- `TestContext` for collecting stdout, stderr, exit code, and telemetry
- `TestOutcome` and telemetry value types
- `TestRegistration` for explicit test registration
- `Registry` for publishing a static test set to Observer
- `sorted_validated_tests` for deterministic ordering and duplicate checks
## When To Use It
Use `observer-rust` if you are:
- building your own Rust-facing test authoring layer
- generating Rust registrations mechanically
- integrating Rust tests into a custom provider host
If you want a ready-made provider host CLI, pair this crate with `observer-rust-host`.
If you want a higher-level authoring library with macros and starter projects, use `observer-rust-lib`.
## Minimal Example
```rust
use observer_rust::{Registry, TestContext, TestRegistration};
fn smoke(ctx: &mut TestContext) {
ctx.write_out(b"ok\n");
assert!(ctx.emit_metric("wall_time_ns", 42.0));
}
struct ExampleRegistry;
impl Registry for ExampleRegistry {
fn tests() -> &'static [TestRegistration] {
static TESTS: [TestRegistration; 1] = [TestRegistration {
canonical_name: "Pkg::Smoke",
target: "pkg::smoke",
function: smoke,
file: file!(),
line: line!(),
module_path: module_path!(),
}];
&TESTS
}
}
```
Before a registry is exposed to Observer, call `sorted_validated_tests::<YourRegistry>()` to enforce the crate's deterministic rules.
## Determinism Rules
- canonical test names must be non-empty
- targets must be non-empty
- canonical names must be unique
- targets must be unique
- final ordering is canonical-name bytes, then target bytes
Those rules are enforced by `sorted_validated_tests` so provider hosts can rely on a stable contract.