ADR 0255: say what review changed — if-capability on offered kinds only, unrenderable pieces left out and named, and why the sampler runs everywhere
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
mesh/delivery-group group feat/the-bar-takes-blocks delivered: every member is delivered

This commit is contained in:
jochen
2026-10-08 14:35:56 +02:00
parent 5852b66988
commit e4299b5521
@@ -67,8 +67,9 @@ and is not the source.
and which fields place a piece. A contribution of that kind gives `data` in that shape instead of
`content`. The holder's claim gives a template for the kind in `renders`: a template over one piece,
written in its tool's grammar. The controller renders each piece through it and places the result.
Each piece is preceded by a comment naming its module, as in ADR 0212 §3. A kind given as text stays
as ADR 0212 decided.
Each piece is preceded by a comment naming its module, as in ADR 0212 §3. The template is given one
function, `quote`, which writes a value as a JSON string with DEL escaped too: a valid basic string in
TOML and in most tools' grammars. A kind given as text stays as ADR 0212 decided.
**2. The holder places a data kind by its placing fields.** The placeholder is
`${contribution:<seat>:<kind>:<field>=<value>,…}`. Within one placeholder, pieces go in the order the
@@ -78,10 +79,19 @@ combination is missing, a contribution is lost. If it is placed twice, the contr
twice. Both are refused at registration. A holder that places none of the kind is not refused. It was
written before the kind existed, and its contributions wait until it places them.
**3. A contribution may name a capability the machine must report: `if-capability`.** The controller
composes it only for a machine whose node-engine reported that capability. Where nothing is known,
there is nothing. This holds for both forms, text and data. The machine's facts decide at composition.
The tool does not decide at run time.
A piece the holder's template renders to nothing, or fails on, is left out of that machine's
declaration and named, with its module and why. This happens to a `shows` the template does not know
yet. The rest of the machine's declaration is sent. Push and plan say which pieces were left out, and
the merge gate refuses a change that leaves out a piece that was placed before.
**3. A contribution of an offered kind may name a capability the machine must report:
`if-capability`.** The controller composes it only for a machine whose node-engine reported that
capability. Where nothing is known, there is nothing. The machine's facts decide at composition. The
tool does not decide at run time.
- The name must be one the node-engine detects. A name nothing detects would leave the piece out on
every machine without a word, so it is refused at registration.
- Only a kind the seat offers (§4) may say it. A kind a holder depends on, such as what a backup keeps
or a key's trigger, is never left out for want of something, so `if-capability` is refused there.
**4. A kind may be offered.** A contribution of an offered kind does not depend on the seat
(an exception to ADR 0212 §4). Where nobody holds the seat, nothing is placed, and the contributor
@@ -111,9 +121,10 @@ block, such as the charge limit asusd holds. None is contributed yet.
**7. The node-engine reports two more capabilities, read from the kernel:**
- `battery`: a battery that powers the machine. A device's battery, such as a mouse's or a headset's,
is not one, and neither is an empty bay.
- `power-meter`: something here measures the power drawn. That is a system battery, a processor
package's powercap energy counter (RAPL, on Intel and AMD), or a graphics device that reports its
own power.
- `power-meter`: something here measures the power drawn, the same meters the power module's sampler
reads. That is a system battery, a processor package's powercap energy counter (RAPL, on Intel and
AMD), or a discrete graphics device that reports its own power. Each package is counted once by its
name, and integrated graphics, which report the package again, are not counted.
**8. The power drawn is measured honestly, and the block says what was measured.**
- **On battery:** the battery's discharge rate. That is the whole machine, and the block says
@@ -122,7 +133,10 @@ block, such as the charge limit asusd holds. None is contributed yet.
change of its energy counter. A discrete graphics device's own power is added where the device
reports it. The block says `CPU` or `CPU+GPU`, never the machine.
- An APU's integrated graphics report the whole package, so they are not counted a second time.
- A sleeping GPU is not woken to be asked.
- A package Intel shows twice (through its MSRs and through MMIO) is read once.
- A sleeping GPU, AMD or NVIDIA, is neither read nor woken to be asked.
- A counter that gives more than 1000 W was reset, after a resume for example. That sample gives no
reading rather than a number that is not power.
- **The machine at the wall** can only be measured by a metered plug or a UPS. It is not measured.
**9. The energy counter stays root's.** Read often, it leaks what the processor is doing (the
@@ -131,6 +145,10 @@ PLATYPUS attack, CVE-2020-8694), which is why the kernel makes it root's. No per
only the averaged rate, as one line anyone may read.
- The bar's command prints that line. It says the power is not measured when the line is missing
or older than thirty seconds.
- **The sampler runs wherever the power module is assigned, servers included.** A server has the
energy counter too, so conditioning the sampler on `power-meter` would not keep it off one. The mesh
has no way to condition a resource on another seat (the bar) being held on the machine, and building
one for a process that reads a few kernel files every five seconds is not worth a new mechanism now.
**10. The memory block shows what programs hold,** not counting the cache. That is the figure
`memory-pressure` judges the same machine by.
@@ -156,6 +174,7 @@ PLATYPUS attack, CVE-2020-8694), which is why the kernel makes it root's. No per
- the machine's draw at the wall, from a metered plug or a UPS;
- a GPU-load block, which belongs to a generic module that does not exist;
- a vendor-only block, such as the laptop's charge limit;
- the sampler on a machine without a bar, until a resource can be conditioned on a seat being held;
- the headsets, which are one person's devices.
## How it is checked
@@ -165,10 +184,15 @@ PLATYPUS attack, CVE-2020-8694), which is why the kernel makes it root's. No per
| A data contribution fits its seat's shape (fields, values, required options, order 0–99), and text and data are not mixed | the catalogue check; the controller's `TestABlockOutsideTheShapeIsRefused` |
| A holder places every combination of the placing fields once, with a template that renders every example | the catalogue check; `TestAHolderPlacesEveryCombinationOnceWithATemplateThatRendersEveryExample` |
| Pieces are rendered by the holder's template, in place and order, each named by module | `TestABlockIsRenderedByTheHolderInItsPlaceAndOrderNamedByModule` |
| `if-capability` places a contribution only where the machine reported the capability, for text and data alike | `TestAContributionIfACapabilityIsPlacedOnlyWhereTheMachineReportsIt` |
| `if-capability` places a contribution only where the machine reported the capability | `TestAContributionIfACapabilityIsPlacedOnlyWhereTheMachineReportsIt`, `TestResolveCarriesTheMachinesCapabilities` |
| `if-capability` names a capability the node-engine detects, on an offered kind only | the catalogue check; `TestIfACapabilityNamesOneTheNodeEngineDetectsOnAnOfferedKindOnly` |
| A piece the holder cannot render is left out and named, and the machine gets the rest | `TestAPieceTheHolderCannotRenderIsLeftOutAndNamedNotTheMachine`; the merge gate refuses a new one |
| The catalogue's bar renders every example of the shape | `TestTheCataloguesBarRendersEveryExampleOfTheShape` |
| `quote` gives a TOML basic string of the same text | `TestQuoteIsATomlBasicStringOfTheSameText` |
| An offered kind makes no dependency on its seat | `TestAnOfferedBlockMakesNoDependencyOnTheBar` |
| `battery` and `power-meter` are read from the kernel, and a device's battery is not the machine's | the node-engine's `power_test.go` |
| The power draw says `machine` only on battery, never counts an APU's graphics twice, and never wakes a sleeping GPU | the power module's `draw_test.go` |
| The power draw says `machine` only on battery, counts each package once, never counts an APU's graphics twice, never reads a sleeping GPU, and gives no reading for a reset counter | the power module's `draw_test.go` |
| The sampler publishes once per interval and stops when told; the bar's script shows only a line under thirty seconds old | `TestTheLoopPublishesEveryIntervalAndStopsWhenCancelled`, `TestTheBarsScriptShowsOnlyAFreshLine` |
| Only a rate leaves root, readable by anyone | the power module's `TestOnlyTheRateIsPublishedReadableByAnyone` |
| The bar's template renders a battery and a quoted command, each bar places both places once, and the memory block uses what programs hold | the i3status-rust module's `blocks_test.go` |
| On the machines | the merge gate's composition of every machine, and after rollout the bar's `i3status_rust_blocks` tool on the laptop and a workstation |