From b225b0762541ec11f7f500e825445e86712aecde Mon Sep 17 00:00:00 2001 From: jochen Date: Mon, 24 Aug 2026 22:54:30 +0200 Subject: [PATCH] ADR 0035 (proposed): a picture is read from what runs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drawing a scenario forced a choice that looks cosmetic and is not. A diagram built from the declaration and captioned "as raised" answers "is what is running what I asked for?" with the request, which always agrees with itself. So: a picture captioned as raised reads only the running system, and where the hypervisor does not hold a fact the picture needs, the raise records it on the resource. With the rule that makes the recording worth anything — a behavioural tag is written after the behaviour works, never at creation, because a failed raise leaves wreckage standing and a picture of wreckage must not badge what the wreckage was supposed to be. It earned itself on the first comparison: every VM showed no addresses, because a container's interface carries the device's name and a VM names its own. The two pictures disagreed, so a whole class of machine silently losing its addresses was visible in seconds. §5 of how-we-build gains the general form, marked proposed. The constitution sync is deliberately NOT done — a rule the mesh enforces before a second person agreed to it is what §6 exists to prevent. --- 00-META/how-we-build.md | 26 +++++ .../0035-a-picture-is-read-from-what-runs.md | 100 ++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 02-DECISIONS/0035-a-picture-is-read-from-what-runs.md diff --git a/00-META/how-we-build.md b/00-META/how-we-build.md index a353a70..696a941 100644 --- a/00-META/how-we-build.md +++ b/00-META/how-we-build.md @@ -172,6 +172,32 @@ quietly stop being true, and nobody will learn that from a document. Not test-driven development as a blanket rule — a test written first against undiscovered behaviour asserts a guess. The obligation is that every decision has a defender. +### A report is read from the system, never from what asked for it + +*Proposed — [ADR 0035](../02-DECISIONS/0035-a-picture-is-read-from-what-runs.md), pending +review.* + +The same rule as the two above, pointed at reporting rather than at verification. **Anything +that describes the state of the mesh — a status view, an inventory, a diagram, a health +check — is assembled from the running system.** Assembling it from the intended state produces +a report that always agrees with itself and can never disagree with reality, which is not a +report. + +Where the system does not natively hold a fact the report needs, **the thing that applied the +fact records it** — and: + +> **A record of behaviour is written after the behaviour works, never when the resource is +> created.** + +Written up front it restates the request in a new place and inherits none of the authority of +having happened. A failed run leaves its wreckage standing, and a report of that wreckage must +not describe what the wreckage was supposed to be. + +This is the production form of the mesh's most expensive fault: a firewall key declared in five +manifests and read by no code +([04-ISSUES/003](../04-ISSUES/003-firewall-scope-is-read-by-no-code/00-report.md)). The +declaration was never wrong. Nothing ever asked the system. + ### Search the record before forming a hypothesis The first action on any error message, failing service or unexpected behaviour is to search the diff --git a/02-DECISIONS/0035-a-picture-is-read-from-what-runs.md b/02-DECISIONS/0035-a-picture-is-read-from-what-runs.md new file mode 100644 index 0000000..91ce780 --- /dev/null +++ b/02-DECISIONS/0035-a-picture-is-read-from-what-runs.md @@ -0,0 +1,100 @@ +--- +status: proposed +date: 2026-08-24 +deciders: jochen +reconstructed: false +extends: 0034-a-test-defends-a-decision.md +--- + +# 35. A picture of a system is read from the system, never from what asked for it + +## Context + +A scenario declaration is a file. A raised scenario is a set of machines, links and rulesets. +The two are supposed to correspond, and the entire value of the lab rests on noticing when +they do not — [ADR 0034](0034-a-test-defends-a-decision.md) says a claim nothing checks is a +claim that will quietly stop being true. + +Drawing a scenario makes that concrete, and forces a choice that looks cosmetic and is not. +A diagram of a running system can be produced two ways: parse the declaration and lay it out, +or interrogate the system and lay *that* out. The first is far easier — the declaration is +already parsed, already validated, already in memory. + +It is also worthless for the only question worth asking of such a picture: *is what is running +what I asked for?* A drawing built from the request and captioned **as raised** answers that +question with the request, which always agrees with itself. + +This is the same fault as +[04-ISSUES/003](../04-ISSUES/003-firewall-scope-is-read-by-no-code/00-report.md) — a firewall key declared in +five manifests and read by no code, so a manifest appears to restrict a port and restricts +nothing. The declaration was never wrong. Nothing ever asked the system. + +## Considered options + +1. **Draw the declaration, and label it honestly.** Cheap, and useful for review before + anything is raised. Insufficient alone: it can never disagree with itself. +2. **Draw the system, inferring the rest from the declaration where the system is silent.** + The tempting middle. Rejected — a picture where some facts are observed and some are + assumed has no honest caption, and the assumed ones are exactly the interesting ones. +3. **Two pictures, one layout, neither borrowing from the other.** Chosen. + +## Decision + +**A picture captioned *as raised* reads only the running system.** It never opens the +declaration, not even for a fact the system happens not to record. + +Where the hypervisor does not natively hold a fact the picture needs — whether a segment is +public, what a gateway translates, whether a machine refuses inbound — **the raise records it +on the resource** as metadata, and the picture reads it back from there. + +That recording carries its own rule, which is the substance of this decision rather than an +implementation note: + +> **A behavioural tag is written after the behaviour works, never when the resource is +> created.** + +Written at creation, a tag restates the request in a new location and inherits none of the +authority of having happened. A failed raise deliberately leaves its wreckage standing, so a +tag written up front would let a picture of that wreckage badge translation the gateway was +never configured to do — reproducing, inside the tool built to catch the fault, exactly the +fault. + +So: the gateway is tagged after its ruleset applies; the machine after the read-back proves +its firewall loaded. + +Both pictures render through **one layout**, so they can be put side by side and the +difference read off directly. + +## Consequences + +- **It earned itself on the first comparison.** Drawn side by side, every virtual machine in + the live picture held no addresses at all. A container's interface carries the name of the + device it was configured as; a virtual machine names its own — so joining addresses to + devices by name attached every address to a container and none to a VM. Nothing failed; + a whole class of machine silently lost its addresses. The two pictures disagreed, so it was + visible in seconds. It is now joined on MAC. +- Raise does more work, and writes metadata it does not itself consume. Accepted: the cost is + a few config keys, and it is what makes a raised instance self-describing. +- A resource raised before a tag existed is missing it. The reader says so rather than filling + the gap from the declaration — an untagged link draws as unknown, not as what the file said + it should be. +- **The rule generalises past diagrams.** Anything reporting on the mesh — a status view, an + inventory, a health check — is subject to it. A report assembled from the intended state is + not a report. +- The declared picture stays, and stays useful: it is review before raising, and it is one half + of the comparison. It carries no runtime status, because it cannot know any. + +- **The constitution sync is not done and must not be.** `how-we-build.md` §5 carries this rule + marked *proposed*, and playbook + [05](../00-META/process/05-constitution-sync.md) publishes the derived page only for rules the + mesh should enforce now. A rule the mesh enforces before a second person has agreed to it is + the failure mode §6 exists to prevent. The sync happens when this record is accepted, and this + line is what makes the gap visible rather than silent. + +## References + +- [ADR 0034](0034-a-test-defends-a-decision.md) — a claim nothing checks stops being true. +- [ADR 0031](0031-the-lab-provides-the-underlay.md) — why the lab must not supply what the + mesh is responsible for; the same instinct, applied to facts rather than to configuration. +- [04-ISSUES/003](../04-ISSUES/003-firewall-scope-is-read-by-no-code/00-report.md) — the fault in production + form.