Files
hq/02-DECISIONS/0261-an-assignment-made-while-its-modules-build-runs-is-kept-pending-and-the-controller-makes-it.md
T
jochen 6dda1b1d77
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
ADR 0261: one condition per pending assignment, and a raised row kept until it clears
The second review of mesh-controller#150 changed points 1, 6 and 7; say
what the code now does.
2026-10-08 16:46:42 +02:00

6.7 KiB

topic, status, date, deciders, reconstructed
topic status date deciders reconstructed
what runs on it accepted 2026-10-08 jochen false

261. An assignment made while its module's build runs is kept pending, and the controller makes it

Context

Since issue 300's fix, a merge that adds a module asks the build seat for it, and the module is registered when the build's outcome is taken in, minutes later. On 2026-10-08 assign was called in that window and answered "no module of that name" (issue 325). The controller kept no record of a build it had asked for until the outcome came back, so it could not tell a build in flight from a typo.

Until now an assignment was always made at the person's act, and refused there if it could not be made. Keeping it for later means the controller makes an assignment after the act, without the person present. That is a new kind of act, and it needs a rule.

Considered Options

  1. Refuse, and say the build is running. The person waits and calls assign again. Rejected: it brings back the second act by hand that issue 300 removed, and nothing reminds the person to make it.
  2. Keep the assignment only when asked (an argument such as wait). Rejected: a person who knows to ask for it already knows the build is running; the one who does not is the one this is for.
  3. Keep the assignment by default while a build is in flight, and have the controller make it when the build registers the module. Chosen.

Decision

  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 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;
    • known, not built: there is a kept request, and its build failed, was not registered, gave no outcome, or could not be asked;
    • unknown: no module registered and no kept request by that name. The answer claims only that, and names the closest names.
  3. In the first case the assignment is kept as a pending assignment, with no argument needed. In the second, assign refuses, and its build argument asks for the build from where the last request came from and keeps the assignment pending on it. If a pending assignment of that module to that machine is already waiting, it is made to wait for the new build; no build is asked that nothing waits on.
  4. The controller makes a pending assignment by the same act as a person's assign, with the same checks, when the build registers the module. It first takes the machine's hold and claims the pending assignment, so a withdrawal cannot land in between. A refusal then ends it as refused. Making it sends nothing, as a person's assign sends nothing.
  5. A pending assignment never waits silently. It expires with the builder's own words when its build fails or is not registered, and with a sentence when no outcome comes within two hours. The controller 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), 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. 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

  • One kind of assignment is now made by the controller, not at the person's act. The person's intention is still the cause: nothing is assigned that a person did not ask for.
  • status lists open pending assignments (and is not well while one is open) and those ended in the last day; the condition carries an assignment not made until it is answered.
  • The controller cannot read the forge. A module directory that no merge announced since this record and no person asked to build still reads as unknown; the refusal says how to build it.
  • A build being registered reads as in flight for five minutes after its outcome. A build recorded and never registered reads so only after that.

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 (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.

References