# A revision signal broadcasts a fact, not an item

> Source: https://github.com/max-listov/stitchkit/blob/master/docs/decisions/0163-a-revision-signal-broadcasts-a-fact-not-an-item.md

---

# 0163 — A revision signal broadcasts a fact, not an item

## Context

Several operations may need to wait until the same process-local fact changes.
An event bus broadcasts callbacks but owns no await, timeout, cancellation or
close lifecycle. A bounded channel retains items for one reader, so using one
turns a broadcast into competition. A credit window waits for ownership of a
finite resource, not for evidence that a fact is newer.

The dangerous interval is between reading the fact and registering the wait. If
the fact changes there, a future-only notification parks the operation until an
unrelated second change.

## Decision

`createRevisionSignal` owns one monotonic safe-integer revision and a required
`maxWaiters`. `advance()` increments the revision and settles every waiter whose
cursor is older. `wait(after)` first compares the cursor with the current
revision: an older cursor resolves immediately, the current cursor may park and
a future cursor is rejected as a caller error.

Every terminal result carries the revision observed at settlement. Change,
timeout, abort, close and capacity are distinct outcomes. Every parked wait has
one settlement path that removes its abort listener, cancels its timer and
releases its waiter slot before resolving.

`close()` is idempotent and settles all retained waits. The signal is a
synchronous handle owned by the resource whose fact it announces; that resource
calls `close()` during its own teardown. A second managed-resource wrapper would
duplicate lifecycle identity without owning another lifecycle.

## Consequences

- One change wakes every observer and is never consumed by the first one.
- Snapshot-then-wait cannot miss an intervening advance.
- Retained memory has an explicit finite count bound and pressure is observable.
- No payload queue, replay history, transport policy or domain vocabulary enters
  the application core.
