mesh-issues: an issue says who works on it, and resolves only from fixing (hq issue 399)
mesh/delivery-group group feat/399-fixing-status checking: 0 of 2 member(s) ready
mesh/merge-gate pass: builds mesh-issues → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery superseded: a newer head of the same pull request

Two agents could start on one issue without seeing each other, and an issue
could be resolved without anyone having said they started its fix. A move to
diagnosing or fixing now names by, the worker as who@node; get and list show
the worker with since and stale; another worker is refused while it is
current unless take-over says why (noted); a worker untouched for
worker-stale-after (24h) may be taken over from without a reason. Resolved is
reached only from fixing. The moved event carries by, since and caller.
Fixing counts as not closed for the triage and the duplicate check.
hq ADR 0283.
This commit is contained in:
jochen
2026-10-10 21:04:32 +02:00
parent a14fa306f2
commit 11afde55d6
14 changed files with 648 additions and 72 deletions
+21 -6
View File
@@ -19,7 +19,7 @@ what it refuses.
| `open` | `title`, `report`, optionally `located-in`, `record` | checks the issue, then takes the next number and keeps it under that number; answers the number |
| `get` | `number` | the issue whole: fields, notes, links |
| `list` | optionally `status`, `owner`, `phrase`, `limit` | short rows, newest first: number, status, owner, title |
| `move` | `number`, `status`, and what that status needs | changes the status under the development cycle's rules |
| `move` | `number`, `status`, and what that status needs (`by` for `diagnosing` and `fixing`, optionally `take-over`) | changes the status under the development cycle's rules |
| `note` | `number`, `text` | appends a note; a note is never edited |
| `link` | `number`, `kind`, `target`, optionally `remove` | adds or removes a typed link |
| `import` | optionally `dry-run`, `commit` | hq's issue folders, read through the records module, each written as an issue under its own number; see below |
@@ -27,12 +27,25 @@ what it refuses.
| `groom` | optionally `pass`, `confirm` | the triage over the backlog: without arguments a dry run in the background, answering its pass id; with `pass` its progress and findings; with `confirm` and `pass` exactly that pass's findings applied, each checked again; see below |
**The cycle's rules, at the write** (hq playbook 03, which `00-META/checks/cycle.py` enforced on the
folders until the import): a status is one of `open`,
`diagnosing`, `located`, `resolved`, `wontfix`; `located` needs `located-in`; `resolved` needs
`located-in` and `fixed-by`; a core issue (located in the controller, the node-engine, the tool runner,
folders until the import, and hq ADR 0283): a status is one of `open`,
`diagnosing`, `located`, `fixing`, `resolved`, `wontfix`; `diagnosing` and `fixing` need `by`; `located` needs
`located-in`; `resolved` is reached only from `fixing` and needs `located-in` and `fixed-by`; a core issue (located in the controller, the node-engine, the tool runner,
the SDK, or the catalogue's bus, forge or build agent) resolves with `replay` or `replay-none`; `wontfix`
needs a `reason`. A refused change changes nothing and says which rule refused it.
**Who works on it** (hq ADR 0283). A move to `diagnosing` or `fixing` names in `by` the issue's **worker**: who
works on it and its node, as `who@node` (such as `fix-399@g14` or `jochen@shanks`, kept in lower case). The issue
keeps its worker (`worker`: `by`, `since`, `active`) while it stays at either status; any other status ends the
work. `get` shows it, with `worker-stale`, and each `list` row shows `worker`, `since` and `stale`. A move to either
status by someone else while the worker is current is refused, naming the worker; with `take-over` saying why, the
issue is taken over, and the reason is noted on it. A worker with no move, note, link or set from a caller on the
issue for `worker-stale-after` (default `24h`) is stale and may be taken over from without a reason, still noted.
The tracker's own writes (the triage, the duplicate check, the delivery notes) keep no worker current. The `moved`
event carries `by` (the worker; who acted, for a move naming none), `since`, `caller` (who acted, as the runtime
proves it: `unproven` today), and `took-over-from`, `take-over` or `released` when they apply. `by` is what the
worker says it is: the runtime does not yet tell a module its caller (hq issue 340), so the worker lets agents and
people see each other; it is not a lock against a false name.
**An issue with a folder in hq** (`record` at open: the folder's name, without the number) is whole in the
tracker like any other: the folder holds its narrative, the tracker its status. Until the import of
slice 3 ran, such an issue kept its status in the folder and `move` refused it; the import filled it.
@@ -45,7 +58,7 @@ with no tools under the node's licence — two questions: a shortlist of at most
then, always, a judgement on the reports: whether it repeats one (`duplicate`, `related` or `none`, whether it is
certain, and why), its **severity** (critical, major, minor), what it **needs** (none, decision, operator), a
suggested owner when it names none, and the shortlisted issues it **depends on** or **relates to**, each with a
one-line reason. Only issues at `open`, `diagnosing` or `located` that are older than the new one are offered.
one-line reason. Only issues at `open`, `diagnosing`, `located` or `fixing` that are older than the new one are offered.
The judgement is kept on the issue (`triage`) and said as the event `triaged` before anything else, then applied
through the module's own `note`, `set`, `link` and `move`, each recorded as by `triage` and each only when not
@@ -91,7 +104,7 @@ the delivery of …", "delivered to every machine it should reach" (covered by a
Delivered is not resolved. When every fix of an issue not yet resolved is delivered, the issue gains a note and the
event `ready-to-verify`, once per set of fixes; it is resolved once its acceptance is proven live. A fix is named
while the issue stays `located`: `move` to the status it has changes what it holds and is refused when it changes
while the issue stays `fixing`: `move` to the status it has changes what it holds and is refused when it changes
nothing.
Every five minutes the module looks for a fix merged and not delivered after `stuck-after` (default `2h`): it is
@@ -206,6 +219,8 @@ verb takes an argument naming a caller, and none can be given one.
and every open branch at the moment the module is switched on. Read once for the counter; the import
reads it as the boundary between the folders hq numbered before the tracker and the numbers the tracker
gave.
- `worker-stale-after` — how long an issue's worker stays current with nothing done on the issue (hq ADR 0283),
as a duration; `24h` when empty.
- `owners` — the registered list `located-in` may name: repositories, and modules as
`mesh-catalog modules/<module>`. An entry of `located-in` is an owner, or an owner followed by a space or a
slash and where in it (`mesh-controller internal/broker`, `mesh-catalog modules/nats/module.json`). A module