pipe-io 1.0.0

Typed source-transform-sink pipelines with backpressure, batching, windowing, and per-stage error isolation. A lightweight runtime-agnostic stream processor for in-process workloads. The missing middle ground between raw iterators and full distributed stream processing.
Documentation
# pipe-io - Migration Guide

> Per-version upgrade notes. The `0.x` line has been additive; no
> breaking source changes shipped between releases. This guide
> captures the *behavioural* changes that consumers should be
> aware of even when source code keeps compiling.

## Contents

- [v0.9.0 -> v1.0.0]#v090---v100
- [v0.8.0 -> v0.9.0]#v080---v090
- [v0.7.0 -> v0.8.0]#v070---v080
- [v0.6.0 -> v0.7.0]#v060---v070
- [v0.5.0 -> v0.6.0]#v050---v060
- [v0.4.0 -> v0.5.0]#v040---v050
- [v0.3.0 -> v0.4.0]#v030---v040
- [v0.1.0 -> v0.3.0]#v010---v030
- [Stability commitment at v1.0.0]#stability-commitment-at-v100

---

## v0.9.0 -> v1.0.0

**Stable release.** The public surface is frozen.

**Source changes:** none required. Existing code compiles
identically.

**What landed:**

- API freeze. The locked `REPS.md` section 4 surface is now
  binding under SemVer. Patch releases (`1.0.x`) ship bug fixes
  only; minor releases (`1.x.0`) are purely additive.
- `cargo-semver-checks` CI job promoted from advisory to a
  **hard gate**. Pull requests that introduce a breaking change
  to the public surface fail CI.
- README rewritten with feature highlights, installation,
  feature-flag table, quick-start snippets per surface
  (basic / batching / windowing / dead-letter / threaded /
  custom driver), and documentation links.
- `REPS.md` section 7 (performance contract) and section 8
  (stability) updated with the locked rules and measured
  numbers. Section 4.9 drops the unimplemented `.buffer(...)`
  reference (rescheduled as `1.x.0` roadmap material).
- `ROADMAP.md` re-anchored: shipped releases listed,
  forward-looking work explicitly marked as post-1.0 minor work.

**Stability rules that take effect now (from `REPS.md` section 8):**

- **Patch (`1.0.x`)** - bug fixes, doc improvements, internal
  performance work, test additions. No new public items.
- **Minor (`1.x.0`)** - pure additions to the public surface,
  new opt-in features, new variants on `#[non_exhaustive]` enums
  reserved for growth, MSRV bumps.
- **Major (`2.0.0`)** - removes, renames, or signature changes
  of public symbols, or non-opt-in runtime dependency additions.

**`#[non_exhaustive]` reminder:** `Error` and `StageFailure` are
non-exhaustive. Match arms on them must include a wildcard:

```rust
match err {
    Error::Source { stage, .. } => /* ... */,
    Error::Stage  { stage, .. } => /* ... */,
    Error::Sink   { stage, .. } => /* ... */,
    _ => /* required - the enum may gain variants in 1.x.0 */,
}
```

**No new public items, no removed items, no renamed items.** The
upgrade is a pure SemVer marker.

---

## v0.8.0 -> v0.9.0

Pre-1.0 stabilization release. No public API changes.

**Source changes:** none required. Existing code compiles
identically.

**What landed:**

- Property tests (`tests/property.rs`, gated on `feature = "std"`).
  These run under `cargo test --all-features` and verify
  invariants across batching, windowing, error policies, and
  driver behaviour with `proptest`.
- Fuzz harnesses under `fuzz/` (excluded from the main workspace).
  Four targets for batching, byte-batching, `Continue` policy,
  and tumbling windows. Require `cargo +nightly fuzz run <target>`.
- CI gains a `semver-checks` job that runs
  `cargo-semver-checks check-release` advisorily. Will be
  promoted to a blocking gate at `v1.0.0`.
- Documentation audit: `docs/MIGRATION.md` (this file) added.

**`proptest` dev-dependency** is new. It is dev-only and does not
affect the published crate or downstream consumers.

---

## v0.7.0 -> v0.8.0

Bridge release. No source changes; documentation and examples
expansion.

**Source changes:** none required.

**What landed:**

- 8 runnable examples under `examples/`.
- `docs/GUIDE.md` user guide.
- `README.md` Quick start + Documentation section.

---

## v0.6.0 -> v0.7.0

Adds the `Driver` trait and `Pipeline::run_with`.

**Source changes:** none required. The trait and `run_with` are
pure additions.

**To start using a custom driver:**

```rust
use pipe_io::driver::{Driver, RunStats, SyncDriver};

struct MyDriver;

impl Driver for MyDriver {
    fn run<S>(self, pipeline: pipe_io::Pipeline<S>) -> pipe_io::Result<RunStats>
    where
        S: pipe_io::Source + Send + 'static,
        S::Item: Send + 'static,
        S::Error: Send + 'static,
    {
        // ... pre/post hooks ...
        SyncDriver::new().run(pipeline)
    }
}

pipeline.run_with(MyDriver)?;
```

**Bound to be aware of:** the `Driver` trait requires `Send` on
the source. For non-`Send` sources, call `SyncDriver::new().run(p)`
directly (inherent method, looser bound). Both built-in drivers
satisfy the trait without changes.

---

## v0.5.0 -> v0.6.0

Wires up `ErrorPolicy::DeadLetter`.

**Source changes:** none required.

**Behavioural change worth noting:**

Before `0.6.0`, `ErrorPolicy::DeadLetter` silently dropped failing
items (it behaved identically to `Continue`). From `0.6.0` onward,
if a dead-letter sink is installed via
`PipelineBuilder::dead_letter(sink)`, failures route to it. If
no sink is installed, the policy still drops silently.

**If you were relying on the silent-drop behaviour:**

- Don't call `.dead_letter(...)` - the silent-drop path is still
  there as the no-sink fallback.
- Or switch to `ErrorPolicy::Continue` explicitly to make the
  intent clear.

**To start collecting failures:**

```rust
use pipe_io::{ErrorPolicy, StageFailure, sink::VecSink};

let dlq = VecSink::<StageFailure>::new();
let dlq_handle = dlq.handle();

pipeline
    .on_error(ErrorPolicy::DeadLetter)
    .try_map(parse)
    .dead_letter(dlq)
    .sink(main_sink)
    .run()?;

for failure in dlq_handle.take() {
    log::warn!("dropped at `{}`: {}", failure.stage, failure.source);
}
```

---

## v0.4.0 -> v0.5.0

Adds the `window` module.

**Source changes:** none required.

**To start using windows:**

```rust
use core::time::Duration;
use pipe_io::{WindowPolicy, Window};

pipeline
    .window(WindowPolicy::Tumbling { size: Duration::from_secs(60) })
    .map(|w: Window<u64>| w.into_inner())
    .sink(writer)
    .run()?;
```

**Constraint to know:** `.window()` and `.window_with()` both
require `T: Clone`. Sliding windows duplicate items across
overlapping windows, and a unified internal stage type made the
`Clone` bound apply uniformly. For non-`Clone` types and tumbling-
only semantics, `.batch(BatchPolicy::new().max_age(...))` is the
substitute.

**No background timer.** Tumbling/Session windows close on the
*next item arriving* after the threshold elapses, or at
end-of-stream. An idle pipeline holding a session window will not
close it until something else happens.

---

## v0.3.0 -> v0.4.0

Polish and benchmarking. No public API changes.

**Source changes:** none required.

**What landed:**

- `benches/pipeline.rs` (hand-rolled, no Criterion).
- `docs/BENCH.md` with measured numbers.
- Performance section in `docs/API.md`.

To reproduce on your hardware: `cargo bench --bench pipeline`.

---

## v0.1.0 -> v0.3.0

The `v0.1.0` release was a scaffold with only `pipe_io::VERSION`
as a public item. `v0.3.0` shipped the entire pipeline surface
(traits, adapters, builder, drivers, batching). There is no
migration path because there was nothing to rename.

A minimal pipeline:

```rust
use pipe_io::{Pipeline, sink::VecSink};

let sink = VecSink::<i64>::new();
let handle = sink.handle();

Pipeline::from_iter(1..=5)
    .map(|n: i32| i64::from(n) * 10)
    .filter(|n: &i64| *n > 20)
    .sink(sink)
    .run()
    .unwrap();

assert_eq!(handle.take(), vec![30, 40, 50]);
```

See [`GUIDE.md`](GUIDE.md) for the full walkthrough and
[`examples/`](../examples/) for runnable code.

`v0.2.0` was a docs-only design-lock pass that landed on `main`
without its own SemVer release. Its content is folded into the
`v0.3.0` CHANGELOG entry.

---

## Stability commitment at v1.0.0

From `1.0.0` forward (see `REPS.md` section 8 for the binding
policy):

- **Patch (`1.0.x`)** - bug fixes, doc improvements, internal
  performance work, test additions. No new public items.
- **Minor (`1.x.0`)** - pure additions to the public surface,
  new opt-in features, new variants on enums reserved for growth,
  MSRV bumps.
- **Major (`2.0.0`)** - anything that removes, renames, or
  changes the signature of a public symbol, or that adds a
  non-opt-in runtime dependency.

CI runs `cargo-semver-checks` against the published baseline
on every pull request and every push to `main`. The job is a
**hard gate** from `1.0.0` onward (advisory under `0.9.x`).
Breaking changes to the public surface fail CI before they can
ship.

This file is updated on every release that ships behavioural or
surface changes worth calling out.