ADR 0261: one condition per pending assignment, and a raised row kept until it clears
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered

The second review of mesh-controller#150 changed points 1, 6 and 7; say
what the code now does.
This commit is contained in:
jochen
2026-10-08 16:46:42 +02:00
parent 3a09387c8e
commit 6dda1b1d77
2 changed files with 23 additions and 13 deletions
@@ -34,8 +34,9 @@ That is a new kind of act, and it needs a rule.
1. **The controller keeps every build request it makes**, once the ask is made and never before, with who
asked it (a merge, a plan, a person's `build`, `assign`), the repository, the directory, the branch and
the merge's commit. A request whose ask could not be made, or whose asker stopped waiting, is kept with
why. A request is kept for 30 days.
the merge's commit. A request whose ask could not be handed over is kept as not asked, with why. One
handed over whose asker stopped waiting is kept as asked with its outcome unknown: the build may still
run, so it reads as in flight until its outcome or the two-hour bound. A request is kept for 30 days.
2. **`assign` of a module the catalogue does not hold says which case it is in:**
- *a build is in flight*: a kept request for the module's directory has no outcome yet (within two
hours of asking), or its build succeeded within the last five minutes and is being registered;
@@ -56,10 +57,16 @@ That is a new kind of act, and it needs a rule.
settles pending assignments on a tick of its own, every minute, and on each build's outcome. A read,
such as `status`, settles nothing.
6. **An assignment that was not made is a condition** (`assignment-not-made`, a warning the operator
resolves). It stays open until it is answered: the module is assigned to that machine later, it is
assigned again and pending on another build, or a person takes it back with `unassign`.
resolves), one per pending assignment: its id names the row, so one row's condition is never cleared for
another's. It stays open until it is answered: the module is assigned to that machine later; a newer
pending assignment of it is open or was made (a newer one that also ended unmade answers nothing, and is
its own condition); or a person takes it back with `unassign`, which takes back every one of that module
on that machine.
7. **`unassign` withdraws a waiting pending assignment.** It is refused, and says so, while the controller
is making one. Ended pending assignments are deleted after 30 days, and a machine's go with it.
is making one. A claim left by a controller that stopped is settled by the tick after five minutes, from
what the mesh holds: made if the module is assigned there, else waiting again. Ended pending assignments
are deleted after 30 days, but one raised as a condition only once that condition is cleared. A machine's
pending assignments are deleted with it, and the tick clears any of their conditions still open.
## Consequences
@@ -75,10 +82,12 @@ That is a new kind of act, and it needs a rule.
## How it is checked
- mesh-controller `cmd/mesh-controller/pending_test.go`: each case of point 2; the claim under the hold and
the refused withdrawal (point 4, 7); a failed ask that never reads as in flight and the asker kept
(point 1); `build` re-pointing a waiting assignment (point 3); a status read that settles nothing, the
tick that does, and a silent build expiring (point 5); the condition raised, and cleared by `unassign` or
a later assignment (point 6); ended rows deleted after 30 days.
the refused withdrawal (points 4, 7); a stale claim settled both ways (point 7); a failed ask that never
reads as in flight, a build no longer waited for that does, and the asker kept (point 1); `build`
re-pointing a waiting assignment (point 3); a status read that settles nothing, the tick that does, and a
silent build expiring (point 5); the condition raised, cleared by `unassign` or a later assignment, and a
second assignment not made keeping its own condition (point 6); ended rows deleted after 30 days, a
raised one kept until its condition clears, and a removed machine's conditions cleared (point 7).
- mesh-controller `internal/inventory/pending_test.go`: a pending assignment goes with its machine.
- `TestReplay325`, R325 in mesh-lab's replays register: the live case of issue 325.
@@ -45,8 +45,9 @@ it.
**The controller keeps every build request it makes, once the ask is made, and `assign` reads them.** A
request is kept with who asked it (a merge, a plan, a person's `build`, `assign`), its repository,
directory and branch, and the merge's commit. A request whose ask could not be made, or whose asker stopped
waiting, is kept with why, so it never reads as a build in flight. Requests are kept for 30 days. The
directory and branch, and the merge's commit. A request whose ask could not be handed over is kept as not
asked, so it never reads as a build in flight; one whose asker stopped waiting may still run, and reads as
in flight until its outcome or two hours. Requests are kept for 30 days. The
outcome is the `build` record with the same id.
An assignment of a module the catalogue does not hold now says which case it is in:
@@ -59,8 +60,8 @@ An assignment of a module the catalogue does not hold now says which case it is
assignment under the machine's hold first, so an `unassign` cannot land in between; an `unassign` while
it is being made is refused and says so. If the build fails, is not registered, or says nothing within
two hours, the pending assignment expires with the build's own words and raises the condition
`assignment-not-made`. That condition stays open until the module is assigned there, assigned again, or
taken back with `unassign`. The controller settles pending assignments on its own one-minute tick and on
`assignment-not-made`, one per pending assignment. That condition stays open until the module is assigned
there, assigned again and pending or made, or taken back with `unassign`. The controller settles pending assignments on its own one-minute tick and on
each build's outcome; reading `status` settles nothing. `status` lists open pending assignments and those
ended in the last day, and is not well while one is open.
- **Known, not built**: said with what came of the last request, and refused. The answer offers `build`,