Measure each fix from the move to fixing to delivered, and say one over its budget (issue 403)
mesh/merge-gate pass: builds mesh-delivery, 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-group group fix/403-fix-time ready: every member ready, and composed together they pass
mesh/delivery superseded: a newer head of the same pull request

hq ADR 0313: the operator's five minutes start when an agent moves the issue
to fixing, not at the merge. mesh-delivery says on each transition, and in
checks, when the pull request opened, when it merged and the class of what it
moves. mesh-issues keeps the first move to fixing, the fix time with its four
phases once the last fix is delivered, serves fix-times, and says
issue-tracker.fix.<class>.over-budget on the operator's channel, cleared by the
next fix of that class within budget.
This commit is contained in:
jochen
2026-10-12 15:50:12 +02:00
parent c5e1bc7bb4
commit 43df7ebc5a
15 changed files with 1342 additions and 31 deletions
+37
View File
@@ -28,6 +28,7 @@ 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 |
| `tracking` | optionally `conditions` (condition keys) | for every condition key an issue links (link kind `condition`), the issues that link it, those not closed first: status, severity, needs, worker with since, active and stale, and where the fix is (`fix`); the operator's channel says it in a condition's message (hq ADR 0285) |
| `reserve` | `kind` (`decision` or `research`), optionally `for` (one line: what the record is about) | the next number of that kind, spent forever; answers `kind` and `number` (and `prefix`, the number as the record's name starts with it); see below |
| `fix-times` | optionally `days` (1 to 90, default 7) | each class's fix budget, the median and worst fix time of the issues whose last fix was delivered in the window, within and over, and every issue over its budget with its longest phase; see *A fix's time* |
**The cycle's rules, at the write** (hq playbook 03, which `00-META/checks/cycle.py` enforced on the
folders until the import, and hq ADR 0284): a status is one of `open`,
@@ -142,6 +143,35 @@ acceptance live, so a fix whose own walk failed and that a later merge carried i
issue resolved or wontfix is never said stuck. A module that runs only
its bundle cannot raise a controller condition (hq ADR 0240 rule 8, ADR 0256), so the warning is the channel's, not the controller's.
## A fix's time (hq ADR 0313)
An issue's **fix time** runs from its first move to `fixing` (kept as `fixing-from`; a take-over or a later move
back to `fixing` does not restart it, and an issue moved before the moment was kept has it read from its log) to the
moment the last of its fixes is delivered. Once every fix it names is delivered, `get` carries it as `fix-time`:
`from`, `end`, `took`, the issue's `class`, its **fix budget** (`budget`: five minutes for a leaf module, ten for a
core one, counted from the move to `fixing`), `over`, the fix delivered last (`fix`), the `worker`, and four
`phases` read from that fix, which add up to the fix time:
| phase | ends at | read from |
|---|---|---|
| implementing | its pull request opened | mesh-delivery's `opened` (the pull request's first head heard) |
| review | the first approval at its head | the forge's reviews (`gitea_pull_reviews`) |
| checks | its merge, required checks and any wait for the merge included | mesh-delivery's `merged_at` |
| merge to running | delivered | the delivery's `delivered` (its delivery time) |
A phase whose end came before the end of the phase before it counts zero; a phase whose end is not known (no
approval at the head on the forge, a delivery that did not say when the pull request opened) is `unknown`, and its
time counts in the next phase, which says so. The class is that of the slowest-budgeted module the fixes move, as
mesh-delivery says it from the delivery plan (`class`: `core`, `leaf`, or `none` for a fix that moves no module);
an issue whose fixes move no module, or whose class is not said, is measured and shown with no fix budget.
**Over its budget is loud.** When the last fix is delivered and the fix time exceeds the class's fix budget, the
operator's channel is told (`seat:operator-channel.notify`, key `issue-tracker.fix.<class>.over-budget`), naming the
issue, its worker and its longest phase. Nothing is said while a fix is undelivered: a merged fix not delivered is
loud as a stuck fix. The warning clears when the next issue of that class is delivered within its budget; the
newest fix time of each class decides, and every sweep says or clears what a failed ask left. The delivery budget
(mesh-delivery's `times`, from the merge) stays a measure inside the fix budget.
## The import of hq's issues (slice 3)
`issue-tracker.import` reads every `04-ISSUES/NNN-slug/00-report.md` of hq **through the records module
@@ -364,6 +394,13 @@ reserve spending nothing, the first reserve refused while the knowledge base doe
set, a kind held none of being no answer, hq's folders never read, and a
reservation that cannot be kept leaving its number spent.
A fix's time is tested in `fixtime_test.go`: the start at the first move to `fixing` through a diagnosis, a
take-over and a move away and back; phases that add up to the fix time, one ended early counting zero and one not
known counted in the next; the class of the slowest fix, none and not known with no budget; no warning while
undelivered, the warning once delivered over budget, cleared by the next of its class within budget and not by
another class, and said at the next sweep when the channel did not take it; `fix-times` over a window, an issue
before it not counted; the start read from the log; and the first approval at the head.
The import is tested over `testdata/hq`, copies of seven real reports of hq chosen for their shapes (a
bracketed list with commas inside parentheses, quoted block items, an apostrophe in prose, a `resolved:`
date, a replay, an empty list, a wontfix): the frontmatter read as written, each issue created at its own