0021. Services follow another service's changes through watches
Status: accepted, 2026-10-21
Context
Services talk in two ways (architecture.md, Communication): synchronous API calls, and events written to
an outbox and delivered to notify, which keeps them for people and their channels. git
(ADR 0020) is the first service whose changes other services must act
on: a push deploys an app, a merge request makes a preview, a pushed folder becomes a docs draft. notify is
built for people (digests, quiet hours, folding repeats), not for driving work. Polling git from every
consumer wastes requests and adds latency, and a message broker is what the architecture defers until
volume demands one.
Decision
- A service whose changes others act on offers watches. A consumer service registers what it follows
with its own service token (
POST /api/v1/watches: the consumer's resource it acts for, the object it
follows, filters). Watches belong to the consumer's service and resource; people see them in the
producer's panel, consumers create and remove them.
- The producer delivers every matching change to
POST <consumer>/api/v1/<producer>/events with its
own service token. Deliveries are rows in the producer's database, written in the transaction that
records the change, sent by a worker with retries and back-off for a day, and visible and retryable in
the producer's panel.
- A delivery carries its id, the change's id and a sequence per followed object, so consumers can be
idempotent and ignore older news. A newer change of the same thing supersedes a delivery not yet sent:
only a branch's newest push matters.
- The consumer answers 2xx once it has stored the delivery (and works on it afterwards), 410 when its
resource is gone (the producer drops the watch), and anything else to be asked again.
- The machinery starts in the first producer, git, and moves to kit when a second producer needs it; the
protocol above is the contract either way.
Consequences
- Reactions across services stay point to point and durable without a broker; ADR 0003's "APIs and
events" gains a third form, and notify stays the people's channel.
- Every consumer exposes one more endpoint, which only the producer's service may call.
- A consumer that was down catches up through the producer's retries; one down for more than a day finds
failed deliveries in the producer's panel and a warning in notify.