Merge pull request 'ADR 0212: a seat says what it receives, and the machine's hotkeys are a seat' (#366) from decision/0212-contributions-to-a-seat-and-hotkeys into main

This commit is contained in:
2026-10-04 14:42:31 +00:00
3 changed files with 113 additions and 0 deletions
@@ -0,0 +1,106 @@
---
topic: the mesh
status: accepted
date: 2026-10-04
deciders: jochen
reconstructed: false
extends: 02-DECISIONS/0210-a-tools-configuration-is-its-seat-holders-and-every-other-module-extends-it-through-the-seat.md
---
# 212. A seat says what it receives, and the machine's hotkeys are a seat
## Context
[ADR 0210](0210-a-tools-configuration-is-its-seat-holders-and-every-other-module-extends-it-through-the-seat.md)
decided that a tool's configuration belongs to its seat's holder, and that every other module extends
it with a contribution to the seat (§2), in a grain the seat defines (§5). The controller knows only
three such grains:
- the environment ([ADR 0203](0203-the-accounts-environment-is-one-modules-and-every-module-contributes-to-it.md));
- shell code in named slots ([ADR 0204](0204-a-module-contributes-shell-code-to-the-login-shell-in-named-slots.md));
- the power moments ([ADR 0211](0211-a-machines-power-is-a-node-seat-its-moments-take-contributions-and-its-states-are-events.md)).
Each was a field of its own, with a renderer of its own. Two more appeared on the first workstation:
- **The window manager.** Four modules, the launcher, the clipboard, the wallpaper and the bar, wrote
files of their own into its include directory, and so did the laptop's model module. That is what
ADR 0210 forbids.
- **The keys the window manager never sees.** A laptop's vendor keys reach only a hotkey daemon, which
reads trigger lines (a key, a state, a command). The daemon's configuration was the laptop module's,
although the daemon is a general piece that more than one module has keys for.
A field and a renderer per grain would make every new seat a change to the controller's schema.
## Considered Options
1. **A field per grain,** as before. Rejected: the manifest and the controller grow with every seat
that takes contributions.
2. **Contributions as files in the holder's drop-in directory,** each contributor writing its own.
Rejected by ADR 0210: a path in another module's territory.
3. **One general contribution: a seat, a kind the seat receives, and text in the tool's own grammar.**
The seat lists the kinds it receives. The holder places each kind with one placeholder, and the
controller concatenates the contributions in module order, each under a comment naming its module.
Chosen.
## Decision
**1. A module contributes with `contributions`.** Each entry names:
- a **seat**;
- a **kind**, which that seat receives;
- **content**, text in the tool's own grammar, which the controller does not read.
**2. A seat lists the kinds it receives,** with the comment prefix of its tool's grammar. A
contribution of a kind its seat does not list is refused at registration.
**3. The holder places a kind with `${contribution:<seat>:<kind>}`** in its own files. The placeholder
is filled with every module's contribution of that kind on the node:
- in module order;
- each preceded by a comment line naming the module;
- empty when there is none.
A placeholder in a module that does not claim the seat is refused, as ADR 0204 refuses shell slots.
**4. A contribution depends on its seat** (ADR 0210 §3), derived and refused as
[ADR 0207](0207-a-module-depends-on-the-node-seats-that-apply-its-resources.md) says.
**5. Two seats receive first:**
| seat | kind | what it is |
|---|---|---|
| `node-display-session` | `config` | window-manager configuration lines: bindings, start-up commands, rules |
| `node-hotkeys` (new, node scope) | `trigger` | hotkey-daemon trigger lines: a key, a state, a command |
`node-hotkeys` is in the mesh's own set. Its holder runs the daemon that sees the keys the window
manager does not, and owns that daemon's configuration and service.
## Consequences
- The window-manager fragments become `config` contributions of their modules: the launcher, the
clipboard, the wallpaper, the bar and the laptop model. The window manager's module places them
instead of including other modules' files.
- A hotkey module holds `node-hotkeys`. The laptop's model module contributes its vendor keys
instead of writing the daemon's trigger file, and keeps only what is its own: the scripts the keys
run.
- The three earlier grains stay as they are. Folding them into this form is a later change, not
required by this record.
- **What got harder:** a contribution is text the controller does not read, so a malformed line
reaches the tool. The holder checks the composed file with the tool's own check where the tool has
one (the window manager's), before it reloads.
## How it is checked
| Rule | Checked by |
|---|---|
| A contribution names a seat and a kind that seat receives | the catalogue check, which registration runs |
| The placeholder fills with every module's contribution, in module order, each named | the controller's contribution tests |
| A placeholder outside the seat's holder is refused | the catalogue check |
| A contribution derives a dependency on its seat | the controller's resolve tests |
| `node-hotkeys` is a node seat of the mesh's own set | the seat table's tests |
## References
- [ADR 0203](0203-the-accounts-environment-is-one-modules-and-every-module-contributes-to-it.md),
[ADR 0204](0204-a-module-contributes-shell-code-to-the-login-shell-in-named-slots.md),
[ADR 0208](0208-the-graphical-session-is-one-module-per-piece-on-the-meshs-seats.md),
[ADR 0210](0210-a-tools-configuration-is-its-seat-holders-and-every-other-module-extends-it-through-the-seat.md),
[ADR 0211](0211-a-machines-power-is-a-node-seat-its-moments-take-contributions-and-its-states-are-events.md)
- [To-be 42](../03-DESIGN/01-to-be/42-the-machines-modules-in-order.md)
+1
View File
@@ -193,6 +193,7 @@ python3 00-META/checks/index.py fail if stale
- **0202** — [A provider declares what it derives for each consumer, and the mesh tells both ends](0202-a-provider-declares-what-it-derives-for-each-consumer.md)
- **0207** — [A module depends on the node seats that apply its resources](0207-a-module-depends-on-the-node-seats-that-apply-its-resources.md)
- **0210** — [A tool's configuration is its seat holder's, and every other module extends it through the seat](0210-a-tools-configuration-is-its-seat-holders-and-every-other-module-extends-it-through-the-seat.md)
- **0212** — [A seat says what it receives, and the machine's hotkeys are a seat](0212-a-seat-says-what-it-receives-and-the-machines-hotkeys-are-a-seat.md)
### Its tiers, from the bottom up
@@ -15,6 +15,7 @@ decisions:
- 02-DECISIONS/0205-software-the-distribution-does-not-package-ships-as-a-pinned-archive-of-the-module.md
- 02-DECISIONS/0207-a-module-depends-on-the-node-seats-that-apply-its-resources.md
- 02-DECISIONS/0208-the-graphical-session-is-one-module-per-piece-on-the-meshs-seats.md
- 02-DECISIONS/0212-a-seat-says-what-it-receives-and-the-machines-hotkeys-are-a-seat.md
- 02-DECISIONS/0211-a-machines-power-is-a-node-seat-its-moments-take-contributions-and-its-states-are-events.md
- 02-DECISIONS/0210-a-tools-configuration-is-its-seat-holders-and-every-other-module-extends-it-through-the-seat.md
---
@@ -111,6 +112,11 @@ not write into its include directory. Each contribution is a dependency on the s
so assigning one of them without a window manager is refused. The first versions, which still write
the include files themselves, move to contributions once the controller derives the dependency.
**Added 2026-10-04.** `triggerhappy` holds `node-hotkeys` on both workstations ([ADR 0212](../../02-DECISIONS/0212-a-seat-says-what-it-receives-and-the-machines-hotkeys-are-a-seat.md)). The
laptop model's vendor keys become its contribution. The window-manager fragments of the launcher, the
clipboard, the wallpaper, the bar and the laptop model become `config` contributions to
`node-display-session`.
## Phase 3 — one machine model
The laptop's hardware module (vendor daemon, GPU mode, charge limit, logind, brightness and vendor keys)