# Release v0.4.0 — Synchronous Foundation
**Date:** 2026-05-19
**Compare:** `v0.1.0...v0.4.0`

## Summary

This release delivers the complete synchronous foundation of `registry-io`,
folding roadmap phases **0.2.0**, **0.3.0**, and **0.4.0** into a single
milestone. With this version, `SyncRegistry` is fully functional,
thoroughly tested, documented end-to-end, and ready for downstream
consumers to begin integrating ahead of the async work in `0.5.0`.

The headline capabilities are: a generic `SyncRegistry<E>` with a
lock-free notify hot path, RAII `HandlerGuard` for automatic
unregistration, descending-priority dispatch with stable ordering on ties,
and panic isolation backed by `std::panic::catch_unwind` plus an optional
`on_panic` callback.

## Added

### Core types

- **`SyncRegistry<E>`** (`src/sync/mod.rs`) — the workhorse registry.
  Generic over the event type `E: Send + Sync + 'static`. Stores handlers
  as `Arc<dyn Fn(&E) + Send + Sync + 'static>` behind an
  `arc_swap::ArcSwap<Vec<HandlerEntry<E>>>`. Public API:
  - `new()`, `with_capacity(usize)`, `Default`, `Debug`.
  - `register(handler) -> HandlerId` (default priority `0`).
  - `register_with_priority(priority, handler) -> HandlerId`.
  - `register_guard(handler) -> HandlerGuard<E>` (requires `Arc<Self>`).
  - `register_guard_with_priority(priority, handler) -> HandlerGuard<E>`.
  - `unregister(id) -> bool`, `clear()`, `contains(id) -> bool`,
    `handler_count() -> usize`, `is_empty() -> bool`.
  - `on_panic(callback)`, `clear_panic_callback()`.
  - `notify(&event)` — `#[inline]`, lock-free, allocation-free in the
    no-panic case.
- **`HandlerId`** (`src/handler_id.rs`) — opaque `Copy + Eq + Hash + Debug
  + Display` identifier. Issued by an atomic-counter generator.
- **`PanicInfo<'a>`** (`src/panic.rs`) — typed wrapper around the
  `catch_unwind` payload, exposing `handler_id()`, `payload()`, and
  `message()`.
- **`HandlerGuard<E>`** (`src/sync/guard.rs`) — `#[must_use]` RAII handle.
  Drops to unregister via a `Weak<SyncRegistry<E>>`; `forget(self)`
  detaches without unregistering. Safe across registry-before-guard drop
  order.

### Priority ordering

- Higher priority values fire first; equal priorities fire in registration
  order (stable). Insertion uses `Vec::partition_point` to maintain the
  invariant without a full re-sort.

### Panic isolation

- Every handler invocation in `notify` runs inside
  `std::panic::catch_unwind(AssertUnwindSafe(...))`.
- Panics in sibling handlers do not interfere with one another or with the
  caller of `notify`.
- An installed `on_panic` callback receives a `PanicInfo` per panicking
  handler, including the handler's `HandlerId` and the raw payload.
- Second-order panics inside the `on_panic` callback are themselves caught
  and discarded.

### Tests

- `tests/smoke.rs` — version + end-to-end smoke.
- `tests/sync_registry.rs` — 16 tests covering register/notify/unregister,
  clear, contains, with_capacity, send/sync, owned captures, stress
  cycles.
- `tests/priority.rs` — 6 tests: descending order, stable ties, extreme
  priorities, mid-priority insert ordering, unregister preserves order.
- `tests/panic_isolation.rs` — 9 tests: non-propagation, sibling survival,
  callback receives id + message, replace/clear, callback panic, custom
  payload downcast, silent default, handler count stability.
- `tests/guards.rs` — 8 tests: drop unregisters, priority variant,
  forget, registry-before-guard safety, multi-guard independence, drop
  prevents handler firing, debug format.
- `tests/concurrent.rs` — 6 tests: 16-thread notify, register-during-notify,
  concurrent register uniqueness, concurrent unregister idempotence,
  stress cycle, deterministic snapshot consistency via `std::sync::Barrier`.

### Benchmarks

- `benches/sync_notify.rs` — handler-count scaling (`0`, `1`, `4`, `16`,
  `64`) and thread-contention scaling (`1`, `4`, `16` threads).
- `benches/register_unregister.rs` — slow-path register and unregister
  latency at varying steady-state sizes.

### Examples

- `examples/basic.rs` — register/notify/unregister.
- `examples/priority.rs` — descending priority ordering.
- `examples/guards.rs` — RAII guard + `forget` semantics.
- `examples/panic_isolation.rs` — panic absorption + `on_panic` callback.
- `examples/concurrent.rs` — 16-thread contention smoke / micro-benchmark.

### Documentation

- `docs/API.md` — every public item documented with parameters, return
  values, and multiple runnable examples per use case.
- `docs/PERFORMANCE.md` — cost model, hot-path code walk-through, slow-path
  rcu pattern, allocation profile, benchmark methodology.
- `README.md` rewritten with working quick-start snippets for the four
  headline use cases.
- All public items carry rustdoc + `# Examples`; `cargo test --doc` passes
  26 doctests.

## Changed

- **MSRV** bumped from `1.75` to `1.85` to be compatible with edition 2024.
  Edition 2024 was stabilized in Rust 1.85, so the previous combination
  was not actually buildable on any released toolchain.
- **Cargo features** restructured: `sync = ["std"]` and
  `async = ["std", "dep:futures-core"]` now make the implication explicit.
- **Bench targets** in `Cargo.toml` updated to point at the two new bench
  files; placeholder `benches/registry_bench.rs` removed.
- **`src/lib.rs`** — added `extern crate alloc`, conditional
  `extern crate std`, `#![warn(clippy::pedantic)]`, and full module
  wiring with re-exports for the public surface.

## Verification

The full local CI gate passes on this milestone:

```
cargo fmt --all -- --check                         OK
cargo clippy --all-targets --all-features -- -D    OK
cargo test --all-features                          OK (47 integration +
                                                       11 unit + 26 doc)
cargo build --examples                             OK
cargo doc --no-deps --all-features                 OK
```

## Roadmap impact

- Phase **0.2.0** (SyncRegistry foundation) — complete.
- Phase **0.3.0** (handler guards + builder-ish capacity) — complete.
- Phase **0.4.0** (priority + panic isolation) — complete.

## Next

- Phase **0.5.0** — `AsyncRegistry<E>` behind the `async` feature flag.
- Phase **0.6.0** — performance verification + tuning.

---

**Full Changelog:** https://github.com/jamesgober/registry-io/compare/v0.1.0...v0.4.0
