ADR 0260: say what review narrowed — one key per grant, per-machine state, wider path roots, a follower that speaks
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered

This commit is contained in:
jochen
2026-10-08 15:54:45 +02:00
parent 427b078093
commit 9afd6f8902
@@ -44,26 +44,44 @@ What the mesh already had:
## Decision ## Decision
**1. Modules talk over the bus, never through each other's files.** No module names a path under **1. Modules talk over the bus, never through each other's files.** No module names a path that
`/run` or `/var/lib` that another module's manifest places. Within one module, parts may pass a file: another module's manifest places under `/run`, `/var/lib`, `/usr/local/lib` or `/etc`. Within one
its root process and its bundle are one module. module, parts may pass a file: its root process and its bundle are one module.
Two exceptions are written down beside the check:
- a short list of paths every program on a machine reads as the machine's own, such as `/etc/hosts`;
- the cross-module reads that stood on the day the rule took `/etc` in. These may only go: there are
five, all the laptop model's module reading the power module's and the hotkey daemon's files.
A path a container sees inside itself is the container's own. The check reads text, so it cannot see
a path built in code from pieces, read from a setting, or reached through a shell the module runs.
**2. A block may show a value its module keeps on the bus.** This adds `shows: state` to ADR 0255 §5: **2. A block may show a value its module keeps on the bus.** This adds `shows: state` to ADR 0255 §5:
- options `state`, naming the state as `<module>.<name>`; - options `state`, naming the state as `<module>.<name>`;
- option `key`, the machine's own name when absent; - option `key`, lower-case letters, digits and hyphens, the machine's own name when absent;
- the value is an object, and its `text` is what is shown. - the value is an object, and its `text` is what is shown.
A module offers only state it keeps itself. A block naming another module's state, or one the A module offers only state it keeps itself. A block naming another module's state, or one the
contributor does not keep, is refused at registration. The holder's template sees `machine`, the node contributor does not keep, is refused at registration. The holder's template sees `machine`, the node
it renders for, so the key needs no setting. it renders for, so the key needs no setting.
**3. The holder is granted the read, without naming the contributor.** The controller derives the **3. The holder is granted the read of one key, without naming the contributor.** The controller
holder's reads per machine: every state that the modules on the holder's machine offer in pieces of a derives the holder's reads per machine: each state that the modules on the holder's machine offer in
kind its seat receives as data. The bar's manifest names no power module. A bar on a machine without pieces of a kind its seat receives as data, and of each only the key the piece shows. The bar's manifest
the power module reads nothing of it. The contributor may write its own state, and the holder may only names no power module, and a bar on a machine without the power module reads nothing of it.
read it, as ADR 0201 already grants. - On the bus the grant is that one key: a direct get of its subject, and a consumer filtered to it.
A client watching one key creates its consumer by the create-with-filter form, which the server
holds to the filter it names.
- Binding to the bucket, deleting a consumer and flow control stay per bucket. None of them reads or
writes a value.
- **State may be per machine.** A state declared `per-machine` is written and read by each machine's
instance at the key named for its machine, and the bus grants that key and no other. The power
module's `draw` is per machine, so a machine's power module can write only its own draw.
- One account per machine carries every module there, so the bus enforces the union of their grants.
For the power draw, that union is still the machine's one key.
- The membership names the key, so the runtime can refuse first. Until it does, the bus refuses.
**4. The power draw is the power module's state `draw`, keyed by the machine.** It holds one value **4. The power draw is the power module's state `draw`, per machine.** It holds one value
per machine, with these fields: per machine, with these fields:
- `text`, the line shown; - `text`, the line shown;
- `watts`; - `watts`;
@@ -77,8 +95,14 @@ four machines that is under one message a second.
**5. The bar shows a bus value in its own way.** For i3status-rust: **5. The bar shows a bus value in its own way.** For i3status-rust:
- the bar's bundle watches each state its bars name; - the bar's bundle watches each state its bars name;
- it leaves the value's text in the bar module's own runtime directory; - it leaves the value's text in the bar module's own runtime directory;
- the block runs the bar module's own command, which prints the text, or nothing when it is more than - it dates each value by its own `at`, not by when it arrived;
30 seconds old, so the block hides. - the block runs the bar module's own command, which prints the text, or nothing when the value was
measured more than 30 seconds ago, so a value frozen at its source hides;
- a watch that says nothing for twice the value's lifetime is read again, and the bundle says so in its
log;
- a refused watch is logged and tried again;
- a value no bar shows any more is dropped. The SDK has no way to end a watch, so a dropped watch
lasts until the bundle restarts, and what it hands over is ignored.
Another bar module would show the same state in its own way. Another bar module would show the same state in its own way.
@@ -100,11 +124,12 @@ power-supply class itself. That is the bar reading the machine, not another modu
| Rule | Checked by | | Rule | Checked by |
|---|---| |---|---|
| No module names a path under `/run` or `/var/lib` that another module's manifest places | the catalogue's `checks/paths`, run by its `merge-check.sh` over every module, and that check's own tests | | No module names a path under `/run`, `/var/lib`, `/usr/local/lib` or `/etc` that another module's manifest places; the known exceptions only shrink | the catalogue's `checks/paths` with its `shared` and `known` lists, run by its `merge-check.sh` over every module, and that check's own tests |
| A block shows only state its contributor keeps | the catalogue check; the controller's `TestAModuleOffersItsOwnStateOnly` | | A block shows only state its contributor keeps | the catalogue check; the controller's `TestAModuleOffersItsOwnStateOnly` |
| The holder is granted the read of what the modules on its machine offer, and nothing more | `TestAStateBlockIsRenderedForThisMachineAndTheHolderIsGrantedToReadIt`; `TestABarIsGrantedTheStateItsMachinesModulesOfferIt` against a real store | | The holder is granted the one key each piece on its machine shows, and nothing more | `TestAStateBlockIsRenderedForThisMachineAndTheHolderIsGrantedToReadIt`; `TestABarIsGrantedTheStateItsMachinesModulesOfferIt` against a real store |
| A keyed read and per-machine state reach one key on the bus, also as the machine's union | the controller's `TestPerMachineStateAndAKeyedReadReachOneKey`, `TestAMembershipNamesTheOneKeyOfKeyedState` |
| Only a fresh reading that measured something is put, keyed by the machine | the power module's `publish_test.go` | | Only a fresh reading that measured something is put, keyed by the machine | the power module's `publish_test.go` |
| The bar keeps a value's text, removes a deleted one, retries a refused watch, and hides an old value | the i3status-rust module's `values_test.go` | | The bar dates a value by its reading, says a refused or silent watch, rereads a silent one, drops a removed block, and hides a value measured more than 30 s ago | the i3status-rust module's `values_test.go` |
## References ## References