From 973182cdf9c33be5782dc7bd6070418049eb0d0e Mon Sep 17 00:00:00 2001 From: jochen Date: Mon, 26 Oct 2026 18:00:18 +0100 Subject: [PATCH] Design 53: milestones are records of the tracker, an issue's milestone is its own link, and the seed reads the design's table once (ADR 0493, issue 1781) --- 03-DESIGN/01-to-be/53-the-issue-tracker.md | 38 +++++++++++++++++++--- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/03-DESIGN/01-to-be/53-the-issue-tracker.md b/03-DESIGN/01-to-be/53-the-issue-tracker.md index dc1f155a..2384326d 100644 --- a/03-DESIGN/01-to-be/53-the-issue-tracker.md +++ b/03-DESIGN/01-to-be/53-the-issue-tracker.md @@ -2,7 +2,7 @@ layer: to-be status: in-progress code: [mesh-catalog modules/mesh-issues, mesh-catalog modules/claude-code, mesh-catalog modules/messenger, mesh-sdk] -updated: 2026-10-11 +updated: 2026-10-26 decisions: - "ADR 0275" - "ADR 0278" @@ -13,6 +13,7 @@ decisions: - "ADR 0291" - "ADR 0294" - "ADR 0300" + - "ADR 0493" --- # 53 — The issue tracker @@ -81,7 +82,10 @@ agent finds them with `mesh_search` ("open an issue") and calls them as `issue-t | `set` | a number and any of `severity`, `needs`, `suggested-owner` | changes them as a person decides (§ 10) | | `tracking` | optionally condition keys | for every condition key an issue links, the issues that link it and where each stands: status, needs, worker, fix (§ 12) | | `groom` | optionally `confirm` and a pass's id | the duplicate check over the backlog (§ 9): without `confirm`, starts a dry run in the background and answers its id; with the id alone, its progress and findings; with `confirm` and the id, applies exactly that pass's findings, each checked again | -| `import` (slice 3) | optionally `dry-run`, a commit | reads every issue folder of hq through the records module and writes each as an issue at its own number; creates what is absent, fills a status the tracker holds empty, never overwrites, never advances the counter; run again, changes nothing and says so | +| `import` (slice 3) | optionally `dry-run`, a commit, and `milestones` with a design's number | reads every issue folder of hq through the records module and writes each as an issue at its own number; creates what is absent, fills a status the tracker holds empty, never overwrites, never advances the counter; run again, changes nothing and says so. With `milestones`, it seeds that design's milestone records from its table instead (§ 13) | +| `milestones` | optionally a design, a status, or one milestone as design/id | the milestone records, each with its issues and their count by status; one milestone with its issues' rows and its history (§ 13) | +| `milestone-set` | a design, an id, an outcome, optionally an order, or `announce` | makes a milestone record, or changes its outcome or order; with `announce`, says the record again as its event (§ 13) | +| `milestone-move` | a milestone as design/id, a status and a reason | opens or closes a milestone; closing is refused while an issue linked to it is neither resolved nor wontfix (§ 13) | Each verb's description says in plain words what it does and what it refuses, without the mesh's internal names, so an agent picks the right one from `mesh_search` alone. A refusal says what was wrong and what would be accepted. @@ -100,8 +104,8 @@ the issue's worker, who works on it, as the worker states it - `located-in`: entries of the registered list of owners (repositories and modules), never free text; - `fixed-by` (pull requests or commits), `amended-design`, `replay` or `replay-none`, and a reason for `wontfix`; - `notes`: appended, each with who wrote it, when, and the text; -- `links`, typed: to another issue (`duplicates`, `relates-to`), a pull request, a decision record, a design, a - condition key (the issue **tracks** that condition, § 12) or a delivery; +- `links`, typed: to another issue (`duplicates`, `relates-to`), a pull request, a commit, a decision record, a design, + a condition key (the issue **tracks** that condition, § 12), a delivery, or the one milestone it belongs to (§ 13); - `documents`: the report, and a diagnosis and a resolution when written, each with its author and date, revised in place with its history kept (ADR 0291); - `record`: the path of the issue's folder in hq, while one exists; none is opened any more, and the folders are @@ -203,6 +207,7 @@ worker; one that stops moves the issue on, or is stale a day later. | The triage fills only what is empty, links no cycle, and an issue is ready only when its dependencies' fixes are delivered | the rows of ADR 0279's "How it is checked" | | The duplicate check acts only on a clear duplicate, never on an older or a resolved issue, once per issue, loudly when it cannot judge | the rows of ADR 0278's "How it is checked" | | An issue's documents are kept whole, with author, date and history, and the import of hq's folders loses nothing (ADR 0291) | the module's tests of `documents` and of the import, one case per document kind; the comparison of every issue with its folder before the folders are removed, written on issue 427. Tracked by issue 427 | +| An issue belongs to at most one milestone, linked only by the verb, and only to an open one (ADR 0493 §2 to §4) | the module's table test of the `milestone` and `commit` link kinds, one case per refusal; the test that the triage and the duplicate check never add a `milestone`, `pull-request` or `commit` link; one integration test that starts the module whole on a real bus and makes, links and refuses | | Live | on the mesh, an agent calls `issue-tracker.open` and gets the next number; two sessions on two nodes open at the same moment and get two different numbers; `list` shows both | ## 8. The slices after the first @@ -312,6 +317,31 @@ with no pull request open is **abandoned**. **tracking line** in every condition's message; the words and the verdict it changes are its own (to-be 45 § 5). The controller learns nothing of issues. +## 13. Milestones + +**A milestone is a record of the tracker, made from its design's table** (ADR 0493 §1). The state `milestones`, which the +manifest declares beside `issues`, keeps one value per milestone, keyed by its design's number and its id: the id as the +design's table writes it, the outcome, its order in the table, its status (`open` or `closed`, with a reason), who made +and who last moved it and when, and the hq commit and path it was seeded from. It is written by compare-and-set at the +revision read, and its history is the key's kept values with the events `milestone-set` and `milestone-moved`. + +**An issue's milestone is the issue's own link, not a list on the milestone.** The link kind `milestone` (its target +design/id, such as 47/R6) is written in the issue's log like any link, so the rule that an issue belongs to at most one +milestone (ADR 0493 §2) is checked inside that issue's one write, refused naming the milestone it is in; a link to a +milestone that does not exist or is closed is refused (§3: a fix found on the way joins the open milestone). A milestone's +issues are read from the issues in memory. Pull requests and commits are linked to the issue they fix the same way, with +the kinds `pull-request` and `commit` (§4); nothing reads them from a description, and the triage never adds one. + +**The seed** is `import` with `milestones` and a design's number: it reads the table through the records module, makes +each record that is absent in the table's order, links each issue it names that has no milestone, refuses (and names) +an issue another milestone holds or two rows name, closes a milestone whose issues are all resolved with their fixes +delivered, and run again changes nothing. Once a design is seeded, the tracker is the only list of its milestones' +issues: the design's table keeps its rows without an Issues column, and the knowledge base's `progress` reads +`milestones` (issue 1781). + +Readiness, the one ask per milestone and its release are the delivery seat's (ADR 0493 §7 to §11, issue 1783); the +tracker gives them the records and links they read. + ## What it leaves out Priorities beyond severity, notifications beyond the `ready` and `ready-to-verify` events and the stuck-fix warning, full-text or semantic search, the forge's own issue lists, and an index of any kind: