# Roadmap

`one_flight` should stay small: the core package is a request-coalescing primitive,
not a cache, HTTP client, retry library, or JSON library. Integrations should be
added only when they make the primitive easier to apply without weakening that
boundary.

## v0.1: Single-node core

Status: implemented.

- Single-node `OneFlight.run/3` and `OneFlight.run!/3`.
- `OneFlight.async/3` and `OneFlight.await/2`.
- `OneFlight.forget/2`.
- `OneFlight.stats/2`.
- Supervised Task execution.
- Per-waiter timeouts.
- Demand-driven cancellation.
- Execution error capture for raise, exit, and throw.
- Telemetry events for collapsed work.

## v0.2: Cluster scope

Goal: keep the same call-site API while coalescing duplicate calls across a
connected Elixir cluster.

- Add `scope: :cluster`.
- Use the two-level design:
  - level 1: local singleflight per node
  - level 2: only local leaders enter cluster coordination
- Use `:global` name registration for level-2 coordination.
- Keep closures local; user functions never cross the wire.
- Add `:peer` tests for simultaneous candidates, leader-node death, and netsplit behavior.
- Document the honest guarantee: at most one execution per connected partition in steady state, with duplicate windows during membership changes.

## v0.3: Req integration

Goal: make outbound HTTP request coalescing ergonomic for projects that already use
Req.

Likely shape:

```elixir
Req.new()
|> OneFlight.Req.attach(name: MyApp.Flights, key: :url)
|> Req.get!(url: url)
```

Use cases:

- duplicate GET requests to the same upstream resource
- rate-limited APIs
- remote configuration fetches
- token introspection
- service discovery endpoints

The integration should let callers choose the key strategy, such as URL only,
method plus URL, or method plus URL plus request body hash.

## v0.4: Finch examples or helper

Goal: support lower-level HTTP users without forcing a Req dependency.

Start with README examples:

```elixir
OneFlight.run({:http, :get, url, headers_hash}, fn ->
  Finch.build(:get, url, headers)
  |> Finch.request(MyFinch)
end, name: MyApp.Flights)
```

Only add a dedicated helper if real users ask for it. A `OneFlight.Finch` module
is less obviously valuable than a Req step because Finch intentionally has a small
low-level API.

## Poison and JSON workloads

Poison is a use case, not an integration target.

Good uses:

- coalesce loading and decoding the same large remote JSON config
- avoid duplicate parse work after a cache miss
- dedupe expensive schema/source transformations keyed by content hash

Avoid a `OneFlight.Poison` module unless a concrete repeated pattern appears.
JSON libraries are easy to wrap with `OneFlight.run/3` directly.

## Possible later work

- `strategy: :ring` for large clusters where `:global` coordination becomes a measured bottleneck.
- `OneFlight.Req` request-key presets for common safe cases.
- Markdown report or telemetry example snippets for observability docs.
- Benchmarks comparing duplicate uncoalesced work vs `one_flight` under hot keys.

## Explicit non-plans

- No result TTL.
- No persistent storage.
- No retry, backoff, or circuit breaking.
- No cache API.
- No distributed consensus dependency.
