Merge pull request 'Issue 275: a machine waiting for its push was said to be urgent' (#142) from issues/275-a-machine-waiting-for-its-push-was-said-urgent into main
mesh/delivery held for a person: merged without a passing check: only a person decides that it goes on
mesh/delivery held for a person: merged without a passing check: only a person decides that it goes on
This commit was merged in pull request #142.
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
---
|
||||
status: located
|
||||
opened: 2026-10-06
|
||||
located-in: [mesh-controller]
|
||||
fixed-by: novox/mesh-controller PR #89
|
||||
amended-design:
|
||||
---
|
||||
|
||||
# 275. A machine waiting for its push was said to be urgent
|
||||
|
||||
## Symptom
|
||||
|
||||
On 2026-10-06 the operator assigned the backup module to the workstation and, a minute later, pushed
|
||||
it. Between the two, the self-check's D1 (to-be 45 §4) raised an **urgent** condition on the
|
||||
workstation, and the operator was notified on the desktop:
|
||||
|
||||
> nothing can be sent to the workstation: its declaration does not compose — restic needs a secret
|
||||
> called "repository" and none was made for it
|
||||
|
||||
The push that followed made the secret, sent the declaration, and the machine applied it. Nothing had
|
||||
been wrong. In the same window D3 raised that the workstation's `node-backup` holder was silent, and
|
||||
D13 that the data declared there was unmeasured — about a holder that had not been sent yet.
|
||||
|
||||
Three conditions, one of them urgent, for the ordinary gap between `assign` and `push`. A condition
|
||||
that fires on normal work teaches the operator to ignore conditions, which is the failure to-be 45
|
||||
exists to prevent.
|
||||
|
||||
## Cause
|
||||
|
||||
**D1 asked a question the push answers.** A module's own secrets — a repository password, a database
|
||||
superuser — are made by the push, on the send path, and only there: a question that wrote would
|
||||
contend with the machine it was asking about (that is why compositions are `Reading` everywhere but
|
||||
the send). D1 composes every machine with a `Reading` composition. For a module assigned since the
|
||||
last push, that composition has no value for its own secret, and the composer refuses a secret it is
|
||||
given no value for. D1 read every refusal as "this machine's declaration does not compose".
|
||||
|
||||
The refusal was right for what it guards — a declaration must never be sent with a credential missing
|
||||
— and wrong as a finding: the push would have made the secret and composed. D1 could not tell "the
|
||||
push makes this" from "the push fails on this", because the refusal was one untyped error.
|
||||
|
||||
**D3 and D13 read the assignment, not the delivery.** Both expected a holder on every machine its
|
||||
module is assigned to. Assigned is not there: the holder exists once the machine was sent a
|
||||
declaration carrying it and applied it.
|
||||
|
||||
## Fix
|
||||
|
||||
The fix is novox/mesh-controller PR #89. The rule:
|
||||
|
||||
**A finding about a machine is about what it was sent, or what the next push would send it — never
|
||||
about the gap between an assignment and its push.**
|
||||
|
||||
- **D1 composes as the push would, making nothing.** An own secret not made yet is judged by the
|
||||
push's own rules. One the push *makes* is composed with a stand-in, and named. One the push is
|
||||
*refused* on — a bus credential nobody issued
|
||||
([issue 203](../203-a-fresh-assignment-is-pushed-before-its-credential-exists/00-report.md)), a
|
||||
machine with no sealing key, a given secret sealed to a key the machine no longer has — is refused
|
||||
in the push's words. Everything else that does not compose, or that the node-engine's validator
|
||||
refuses, is still found, and is still urgent: the stand-in hides nothing.
|
||||
- **A machine that composes only with stand-ins is waiting for a push, not broken.** Nothing is said
|
||||
for thirty minutes from when it began waiting — the oldest assignment since its last send, or that
|
||||
send. Past that, a **warning**, `awaiting-push`, names what the next push will make and the verb
|
||||
that sends it. Never urgent: nothing is wrong that a push does not fix.
|
||||
- **The composer's refusal is typed.** A secret given no value is its own error, carrying the module
|
||||
and the name; no caller reads the words.
|
||||
- **D3 and D13 expect a holder once it was delivered.** A holder is expected to answer on a machine
|
||||
when the machine's last send carried its module and the machine has reported acting on that
|
||||
declaration, or has had ten minutes to. A machine sent nothing is expected to hold nothing the mesh
|
||||
put there. A send recorded before the mesh kept what it carried is read as before.
|
||||
|
||||
## How it is checked
|
||||
|
||||
Tests in the controller run through its real stores:
|
||||
|
||||
- **The window.** A machine is pushed, then a module with an own secret is assigned to it. The read
|
||||
composition refuses with the typed error; the composition asked ahead of the push composes, names
|
||||
the secret, and makes nothing. D1 says nothing within the bound, a warning past it, and nothing once
|
||||
the machine is pushed. Without the fix this test fails with the urgent text seen live.
|
||||
- **A real failure stays urgent.** A module whose bus credential was never issued, a given secret
|
||||
under an old key, and a machine whose set does not resolve beside a waiting secret are each still
|
||||
urgent `uncomposable`.
|
||||
- **When a holder is expected.** Never sent, sent without it, sent and not yet reported, reported,
|
||||
and sent long ago without a report each give the expected answer, read from the send and report
|
||||
records.
|
||||
|
||||
## Left open
|
||||
|
||||
- **To-be 45's D1 row** still states only "every machine's declaration composes". It should say that
|
||||
a composition waiting only on what the next push makes is not a failure, and name the
|
||||
`awaiting-push` warning. An amendment via playbook 02, not made here.
|
||||
- **Ports.** A module's machine port is also chosen only on the send path. A composition that reads
|
||||
composes an unchosen port at the module's own number; that has raised nothing so far, but it is the
|
||||
same gap, and the stand-in rule would apply to it if a port ever made D1 refuse.
|
||||
Reference in New Issue
Block a user