Any hosted service can be a factory — an identity provider grants clients, an analytics service grants a tracking identity, a mail server grants mailboxes, an application platform grants a project that is several of those at once. Providing is a FACET a module may have, not a kind of module it is, which is the same conclusion this effort reached about services and applications arriving from the other direction. So `provider` stops being a category too. Two relational stores from different vendors both grant "a database" and are the sharpest possible test of the substitutability rule. They fail it completely — different protocol, dialect, driver, client library compiled into the consumer — so `database` stays a tag, now with two real providers rather than a thought experiment. The assignment is a third entity, recorded because the operator tried the alternative: modules were once node-agnostic and it did not survive. Several of a provider's properties belong to neither end — where its state lives, how it is reached, tuning derived from the machine's hardware, which instance serves a given consumer. Not the catalogue, because they differ per node; not the node, because they are about this module. A design with only modules and nodes has nowhere to put them, which is what node-agnostic ran out of. The current system already stores environment values per module AND per node, arriving the same way. Which answers the question asked directly: two nodes both run a store, so which serves a consumer? Neither obvious answer. Not the consumer naming a node — that is placement in the consumer's manifest, a game edited because a database moved. Not the consumer not caring — for presence it genuinely does not, for instantiation it cares permanently. What the consumer knows is the SCOPE of its own need: one instance shared across every instance of itself, or one each. That decides, and needs no node named. Then the mesh binds, and the binding is recorded on the assignment and is sticky — a resolver that re-derives which store serves a consumer will one day derive a different answer and relocate a database.
01-RESEARCH
Investigations that have not yet hardened into design.
Structure
Each effort lives in NNN-descriptive-name/ and must contain 00-overview.md, carrying its
state in YAML frontmatter and a prose summary below it:
---
status: active | graduated | abandoned
initiated: YYYY-MM-DD
touches: [] # design docs, subsystems or areas the effort bears on
became: [] # required when status is terminal — what it turned into
---
The prose says what is being investigated, why, and what it touches. It does not restate the status — status lives in one place, and two places is one too many.
Further documents in the same folder hold the work itself: notes, evidence, option analyses, draft designs.
Lifecycle
| status | Meaning |
|---|---|
active |
Investigation in progress. |
graduated |
Checked against 00-META, decided in 02-DECISIONS/, and specified in 03-DESIGN — see became:. |
abandoned |
Stopped or superseded. Nothing is deleted. |
An effort graduates by producing a decision record and a 03-DESIGN entry. It is abandoned
in place — never deleted. What was rejected, and why, is the more expensive half to
rediscover.
Starting and closing efforts is playbook territory:
00-META/process/01-research.md and
02-graduation.md.
Rules
- Markdown only. Do not skip or reuse a sequence number.
- Evidence, not assertion. An effort that measured nothing has not finished.
- Research describes real observations but never identifies the mesh it observed. The shape of a finding survives anonymisation intact.