Reconcile: adopt initialization's consolidated HQ as canonical, re-home this session's new work #24
@@ -53,8 +53,8 @@ and receiving credentials. Same edge.
|
|||||||
**Provider stops being a category.** Any hosted thing can be a factory — an identity provider
|
**Provider stops being a category.** Any hosted thing can be a factory — an identity provider
|
||||||
grants clients, a mail server grants mailboxes. It is a facet, not a kind.
|
grants clients, a mail server grants mailboxes. It is a facet, not a kind.
|
||||||
|
|
||||||
**A module may also declare exclusion**, because some things cannot coexist on one machine and
|
**A module may also declare what it claims**, because some things cannot coexist and that is a
|
||||||
that is a fact about the module rather than about a particular node.
|
fact about the module rather than about a particular node. What that means precisely is below.
|
||||||
|
|
||||||
### Why the build edge is a different kind
|
### Why the build edge is a different kind
|
||||||
|
|
||||||
@@ -82,6 +82,92 @@ and the values are derived onto the consumer. **Neither the credential nor the t
|
|||||||
written by hand.** A requirement may name a provider on another node, so cross-node wiring is the
|
written by hand.** A requirement may name a provider on another node, so cross-node wiring is the
|
||||||
same declaration.
|
same declaration.
|
||||||
|
|
||||||
|
## What a module claims, and why it is not a list of rivals
|
||||||
|
|
||||||
|
*Written 2026-08-29, replacing pairwise exclusion.*
|
||||||
|
|
||||||
|
**Exclusivity is not a property of a module. It is a property of a singular resource the module
|
||||||
|
takes over.** Two shells do not compete for anything and any number may be installed. Two display
|
||||||
|
servers both want the seat, and only one may have it.
|
||||||
|
|
||||||
|
> **A module declares what it *claims*. Two modules claiming the same thing cannot both be
|
||||||
|
> assigned within that claim's scope.**
|
||||||
|
|
||||||
|
**Not "xorg conflicts with wayland".** Pairwise exclusion has a property that only shows up later:
|
||||||
|
adding a third display server means **editing xorg and wayland to know about it**. Every new
|
||||||
|
module requires changing modules nobody who wrote it owns, and the edits grow as the square of
|
||||||
|
the count. With a claim, the third one says `claims: the seat` and nothing else changes anywhere.
|
||||||
|
**The new module is the only thing that has to know anything** — which is the difference between
|
||||||
|
a catalogue that grows and one that calcifies.
|
||||||
|
|
||||||
|
The pattern is common enough to be worth listing, because seeing it is most of understanding it:
|
||||||
|
|
||||||
|
| these coexist | these claim one thing |
|
||||||
|
|---|---|
|
||||||
|
| shells — bash, zsh, fish | display servers — xorg, wayland (*the seat*) |
|
||||||
|
| editors — vim, emacs, helix | init — systemd, openrc (*pid 1*) |
|
||||||
|
| language runtimes | container runtime — docker, podman |
|
||||||
|
| terminal emulators | reverse proxies — nginx, caddy, traefik (*ports 80/443*) |
|
||||||
|
| browsers | time — chrony, timesyncd, ntpd (*the clock*) |
|
||||||
|
| | resolvers — resolved, dnsmasq, unbound (*`/etc/resolv.conf`*) |
|
||||||
|
| | network management — NetworkManager, networkd, netctl |
|
||||||
|
| | mail — postfix, exim, msmtp (*port 25*) |
|
||||||
|
| | audio — pipewire, pulseaudio (*the device*) |
|
||||||
|
|
||||||
|
**A claim has a scope**, because not everything singular is singular per machine:
|
||||||
|
|
||||||
|
| scope | example |
|
||||||
|
|---|---|
|
||||||
|
| **node** | the seat, pid 1, port 443 |
|
||||||
|
| **site** | a DHCP server on a segment |
|
||||||
|
| **mesh** | the hub, the control plane |
|
||||||
|
|
||||||
|
The last is not new — the mesh already enforces exactly one hub with a unique index
|
||||||
|
([ADR 0007](0007-connectivity.md)). Scope is that idea, said once rather than hard-coded per case.
|
||||||
|
|
||||||
|
**Some conflicts need no claim at all.** Two modules declaring the same file, or binding the same
|
||||||
|
port, are visible from *what they declare* — the mesh already holds every resource of every
|
||||||
|
declaration. So a claim is only written for the abstract ones, where nothing in the declaration
|
||||||
|
reveals the clash. That keeps the manifest small, which is worth protecting.
|
||||||
|
|
||||||
|
## A requirement with several answers is refused, never guessed
|
||||||
|
|
||||||
|
A module requiring *a shell* may be satisfied by three. The mesh does not pick.
|
||||||
|
|
||||||
|
| candidates | what happens |
|
||||||
|
|---|---|
|
||||||
|
| exactly one | assigned, silently — there was no choice to make |
|
||||||
|
| none | refused, naming what is missing |
|
||||||
|
| several | **refused, naming them**, and a person chooses |
|
||||||
|
|
||||||
|
**This is what makes a solver unnecessary.** Counting candidates is a few lines and has no
|
||||||
|
surprising behaviour; a solver that picks has to be understood before its answer can be trusted,
|
||||||
|
and it is understood by whoever is debugging it at the time. Nothing here is lost by waiting —
|
||||||
|
a solver can be added later without changing a single manifest, and the reverse is not true.
|
||||||
|
|
||||||
|
**Requiring a module and requiring a capability are different fields**, because the remedies
|
||||||
|
differ and the message should say which:
|
||||||
|
|
||||||
|
- *i3 needs xorg, which is not assigned here* — assign it.
|
||||||
|
- *this machine has no seat* — wrong machine; nothing can be installed to fix it.
|
||||||
|
|
||||||
|
## "Flavor" is retired
|
||||||
|
|
||||||
|
It was carrying three unrelated meanings — variants of a thing, a subset of one module a node
|
||||||
|
installs, and whatever the current system does, which earned two knowledge-base entries about
|
||||||
|
going wrong. **A word with three meanings cannot be reasoned about**, and every attempt to design
|
||||||
|
around it produced a rule that was right for one meaning and wrong for the others.
|
||||||
|
|
||||||
|
What it was reaching for is two ordinary things:
|
||||||
|
|
||||||
|
- **Different modules that provide the same thing.** `zsh` and `fish` both provide *a shell*. They
|
||||||
|
are two modules, not one module with a switch: they share a name and nothing else — different
|
||||||
|
packages, different configuration, different everything.
|
||||||
|
- **One module with a setting.** A monitoring module that is an agent here and a server there is
|
||||||
|
one module, configured. Nothing varies but a value.
|
||||||
|
|
||||||
|
If something is neither, it is probably two modules.
|
||||||
|
|
||||||
## The core library is the mesh's domain
|
## The core library is the mesh's domain
|
||||||
|
|
||||||
One module everything may depend on. It holds **what is true of the mesh regardless of which
|
One module everything may depend on. It holds **what is true of the mesh regardless of which
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ The decomposition is impossible while a feature is a singleton per module.
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 1.1 | Decision record — named features, per-node opt-in (next free number) | accepted |
|
| 1.1 | Decision record — named features, per-node opt-in (next free number) | accepted |
|
||||||
| 1.2 | Manifest: declared `features:` with type + directory | a module declares two of one kind and both build |
|
| 1.2 | Manifest: declared `features:` with type + directory | a module declares two of one kind and both build |
|
||||||
| 1.3 | Selection: `always` / flavor-selected / `optional` | a node installs a subset; artifacts stay flavor-blind |
|
| 1.3 | Selection: `always` / `optional` | a node installs a subset; artifacts stay selection-blind |
|
||||||
| 1.4 | `requires:` moves onto the feature | a schema feature's database is not provisioned where the feature is not installed |
|
| 1.4 | `requires:` moves onto the feature | a schema feature's database is not provisioned where the feature is not installed |
|
||||||
| 1.5 | Assignment carries the opted-in feature set | opting a node in requires no rebuild |
|
| 1.5 | Assignment carries the opted-in feature set | opting a node in requires no rebuild |
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ Cheapest first, and each one proves the extraction pattern before the expensive
|
|||||||
| 2.2 | `hal/stream` — the record; notifications and messaging as views | axon, synapse, notifications, meetings, conversations | medium |
|
| 2.2 | `hal/stream` — the record; notifications and messaging as views | axon, synapse, notifications, meetings, conversations | medium |
|
||||||
| 2.3 | `hal/agents` — identity, licence, runs, memory, thoughts | noxflow agents, `hal/thoughts` | **high** — touches credentials |
|
| 2.3 | `hal/agents` — identity, licence, runs, memory, thoughts | noxflow agents, `hal/thoughts` | **high** — touches credentials |
|
||||||
| 2.4 | `hal/work` — what remains of noxflow | noxflow tasks | medium |
|
| 2.4 | `hal/work` — what remains of noxflow | noxflow tasks | medium |
|
||||||
| 2.5 | `hal/ai` — provider integration, flavored | `hal/claude*` | medium |
|
| 2.5 | `hal/ai` — one module per provider, each providing *a model provider* | `hal/claude*` | medium |
|
||||||
|
|
||||||
Each extraction is expand-then-contract: new context alongside, dual-write, verify, cut
|
Each extraction is expand-then-contract: new context alongside, dual-write, verify, cut
|
||||||
over, remove. **Never a move commit.**
|
over, remove. **Never a move commit.**
|
||||||
|
|||||||
Reference in New Issue
Block a user