ADR 0110 decided each assignment records where its requirements are answered from; the control plane keeps only a per-machine pin (none recorded) and resolves every requirement implicitly. Harmless with one provider; a second one silently moves consumers' data.
3.0 KiB
status, opened, located-in, fixed-by, amended-design
| status | opened | located-in | fixed-by | amended-design | ||
|---|---|---|---|---|---|---|
| open | 2026-09-30 |
|
161 — An assignment does not record which provider answers it
What was observed
Planning ace's modules that need a database (baserow, letta, n8n, and the apps using ace's
predecessor postgres). The operator's model — and ADR 0110's — is that an assignment states where
each of its requirements is answered from: gitea's assignment on novox says its postgres-database
comes from novox; an app assigned to ace says whether its database comes from ace or from novox.
The mesh holds no such statement for any assignment. Read on novox (2026-09-30):
select … from provision_pin; -- 0 rows
Every requirement in the mesh resolves implicitly, each time, by ADR 0084's order (a pin, then the provider on the consumer's own node, then the only provider).
What was decided, and what exists
Where several remain and none is local, a person chooses when the module is assigned. Assignment lists the candidates, with the holder of a seat that delivers the provision suggested first, and records the answer on the assignment as its pin. Without an answer the module is not assigned.
What the control plane implements:
| decided | implemented |
|---|---|
| the answer is recorded on the assignment | provision_pin is keyed (node, name) — one answer per machine per provision, shared by every module on it |
| chosen at assignment | assign <node> <module> takes no provider; pin <node> <provision> <from-node> is a separate command |
| an assignment may be answered from its own machine (gitea ← novox) | pin refuses a machine pinning to itself ("does not need saying") |
| every assignment has an answer | none recorded; resolution guesses the same answer every time |
Consequence
Nothing is wrong today — with one postgres provider, every guess is the intended answer. But the answer is not a fact anyone stated, so:
- it changes silently the day a second provider appears (e.g. a postgres assigned on ace): every unpinned consumer re-resolves — a consumer on ace moves from novox's database to an empty one on ace at the next push, which is data a module stops seeing without anything saying so;
- two modules on one machine cannot take one provision from different providers;
- a person reading an assignment cannot see where its data lives.
What would be right
ADR 0110 as written: assign records, per requirement, the node that answers it (its own node
included), offering the candidates and refusing an assignment without an answer where several exist;
the per-machine provision_pin becomes a per-assignment record, with existing assignments backfilled
from what they resolve to now so nothing moves.