From e4299b5521a7ec36c98654bc9671332a4c8f1bcd Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 8 Oct 2026 14:35:56 +0200 Subject: [PATCH] =?UTF-8?q?ADR=200255:=20say=20what=20review=20changed=20?= =?UTF-8?q?=E2=80=94=20if-capability=20on=20offered=20kinds=20only,=20unre?= =?UTF-8?q?nderable=20pieces=20left=20out=20and=20named,=20and=20why=20the?= =?UTF-8?q?=20sampler=20runs=20everywhere?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ardware-placed-where-the-machine-has-it.md | 48 ++++++++++++++----- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/02-DECISIONS/0255-the-bar-takes-blocks-as-data-from-the-module-that-knows-the-hardware-placed-where-the-machine-has-it.md b/02-DECISIONS/0255-the-bar-takes-blocks-as-data-from-the-module-that-knows-the-hardware-placed-where-the-machine-has-it.md index aff80b96..b6c69817 100644 --- a/02-DECISIONS/0255-the-bar-takes-blocks-as-data-from-the-module-that-knows-the-hardware-placed-where-the-machine-has-it.md +++ b/02-DECISIONS/0255-the-bar-takes-blocks-as-data-from-the-module-that-knows-the-hardware-placed-where-the-machine-has-it.md @@ -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:::=,…}`. 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 |