# race

Runs two streams concurrently until one emits, then mirrors the winner and
interrupts the other.

A failure or completion from one side before the other emits does **not**
win unless every side ends without emitting. After a winner is chosen, that
stream's later failures are propagated.

## Signatures

```ts
export declare const race: {
    <AR, ER, RR>(that: Fx<AR, ER, RR>): <AL, EL, RL>(self: Fx<AL, EL, RL>) => Fx<AL | AR, EL | ER, RL | RR>;
    <AL, EL, RL, AR, ER, RR>(self: Fx<AL, EL, RL>, that: Fx<AR, ER, RR>): Fx<AL | AR, EL | ER, RL | RR>;
};
```

## Why

`race` selects a live producer by its first useful value rather than by setup,
completion, or a fast failure. This is suitable for redundant sources where a
producer that ends silently should not prevent another from becoming useful.

## Selection, ordering, and cardinality

Both inputs start concurrently. The first emitted value atomically selects its
producer; that value and all later values from the winner are forwarded in
order. The loser emits nothing after selection and is interrupted. There is no
buffering or replay.

## Ownership and lifetime

Before a winner, a non-interruption failure is remembered but does not win; it
is reported only if both inputs end without a value. After selection, winner
failures are forwarded. Both environments remain required. The observing
fiber owns both child fibers and interruption cancels the race and finalizers.

## Examples

```ts
import { Fx } from "@typed/fx"
import { Effect } from "effect"

const response = Fx.race(
  Fx.ensuring(Fx.at("slow", "50 millis"), Effect.log("slow closed")),
  Fx.ensuring(Fx.at("fast", "5 millis"), Effect.log("fast closed"))
)
Effect.runPromise(Fx.collectAll(response)).then(console.log)
// "slow closed" proves loser cleanup; the winning finalizer also runs
// resolves ["fast"]
```
