030 — asking what a machine should be re-signed its certificate
Composing a declaration signed the machine's certificate anew each time, and a signing carries a fresh random serial — so what the mesh would send differed from what it had sent by one byte, for ever, and every machine carrying a certificate stood eternally waiting. Third find of the same rule: issued once and kept. The port had it, the secret had it, the certificate composed fresh on every asking — and the keeping column had existed since the serving-key migration, written by nothing, the same shape ReleasePorts was found in. Found by keeping the scenario standing and diffing two plans seconds apart: one line, where four theories had none.
This commit is contained in:
@@ -0,0 +1,56 @@
|
|||||||
|
---
|
||||||
|
status: fixed
|
||||||
|
opened: 2026-09-01
|
||||||
|
located-in: [mesh-control]
|
||||||
|
fixed-by: mesh-control 38d4e77
|
||||||
|
amended-design:
|
||||||
|
---
|
||||||
|
|
||||||
|
# 030 — Asking what a machine should be re-signed its certificate
|
||||||
|
|
||||||
|
## Symptom
|
||||||
|
|
||||||
|
Every machine carrying a certificate reported as *waiting* — not running what the mesh would send
|
||||||
|
it — for ever. Pushed seconds ago, already behind again. Nothing wrong, nothing failed, nothing
|
||||||
|
quiet; only a comparison that never came out equal.
|
||||||
|
|
||||||
|
It surfaced as the one red test in four consecutive runs, and wore three other faults' clothes
|
||||||
|
first: a test racing the apply it asserted on, a status command that wrote to the database it was
|
||||||
|
reading, a machine starved at its default size. Each was real; each was fixed; the symptom stayed.
|
||||||
|
|
||||||
|
## Cause
|
||||||
|
|
||||||
|
The mesh signs a certificate for a machine's internal name as part of composing its declaration —
|
||||||
|
and signed **anew on every composition**. Same authority, same key, same name, same validity
|
||||||
|
window; a fresh random serial each time, because that is what signing does. So the declaration
|
||||||
|
composed to answer *is this machine current* differed from the declaration sent by exactly one
|
||||||
|
serial number, every time, deterministically.
|
||||||
|
|
||||||
|
The comparison is a digest, so one changed byte is as unequal as a different world.
|
||||||
|
|
||||||
|
## How it was found, which is the lesson
|
||||||
|
|
||||||
|
Not by deduction — deduction produced the three wrong theories above. The suite was run once with
|
||||||
|
its scenario kept standing, and the standing mesh was asked twice: `plan`, `plan`, diff. Two
|
||||||
|
answers seconds apart, identical to the byte but for one serial, in the certificate file. The
|
||||||
|
diff had one line where four theories had none.
|
||||||
|
|
||||||
|
A verdict machine that can be kept and interrogated is worth more than the verdict.
|
||||||
|
|
||||||
|
## The rule it broke, third find of its kind
|
||||||
|
|
||||||
|
**Issued once and kept.** The port had it, the secret had it, the certificate did not — composed
|
||||||
|
fresh on every asking, by the same code that holds the other two still. And like
|
||||||
|
[`028`](../028-two-things-want-one-port-and-nothing-says-so/00-report.md)'s ReleasePorts, the
|
||||||
|
keeping was designed and never wired: the serving-key migration added a column *"and what was
|
||||||
|
issued for it"*, and nothing wrote it.
|
||||||
|
|
||||||
|
A kept certificate stands while the name, the key and the clock agree. A node that rejoined with
|
||||||
|
a new key or changed its name gets a fresh signing exactly as if nothing were kept; so does one
|
||||||
|
whose certificate is into its last tenth of life.
|
||||||
|
|
||||||
|
## Verified
|
||||||
|
|
||||||
|
Live, on the kept mesh, before any suite run: one push with the fixed binary and the machine
|
||||||
|
settled; the second machine likewise; then the mesh's own sentence — all doing what they were
|
||||||
|
told, running what the mesh would send them.
|
||||||
Reference in New Issue
Block a user