ADR 0035 (proposed): a picture is read from what runs
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.
This commit is contained in:
@@ -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
|
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.
|
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
|
### Search the record before forming a hypothesis
|
||||||
|
|
||||||
The first action on any error message, failing service or unexpected behaviour is to search the
|
The first action on any error message, failing service or unexpected behaviour is to search the
|
||||||
|
|||||||
@@ -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.
|
||||||
Reference in New Issue
Block a user