diff --git a/.claude/skills/hq-new-issue/SKILL.md b/.claude/skills/hq-new-issue/SKILL.md index d6c90aca..499ece60 100644 --- a/.claude/skills/hq-new-issue/SKILL.md +++ b/.claude/skills/hq-new-issue/SKILL.md @@ -21,9 +21,28 @@ Opens a numbered issue. **Authoritative playbook:** there, this is not an issue — it is a lookup. If the answer is a general lesson, it belongs in both. +## The number comes from the issue tracker + +Every issue is opened in the issue tracker (seat `issue-tracker`, module `mesh-issues`, ADR 0275). **Never take a +number by reading `main` or the open pull requests** — that is how numbers collided. If the tracker cannot be +reached, take no number and say so. + +Decide the shape first: + +- **Design or governance issue** — its narrative belongs in hq: it gets a folder `04-ISSUES/NNN-short-name/`. +- **Anything else** — it lives wholly in the tracker, and nothing is written in hq. + ## Steps -1. Next free number. Create `04-ISSUES/NNN-short-name/00-report.md` with: +1. Load `mesh_call` and `mesh_describe` (deferred tools of the `mesh` MCP server) and open the issue: + `mesh_call issue-tracker.open` with `title` (the symptom in one line), `report` (what was seen, what was expected, + how it was found — the evidence: what was run, what came back, when), optionally `located-in` when the owner is + already known, and — **only for an issue with a folder** — `record: short-name` (lower-case words joined by + hyphens, no number). The answer carries the number `NNN`. +2. **Issue wholly in the tracker:** done. Its trail goes in `issue-tracker.note`, its status changes through + `issue-tracker.move`, its links through `issue-tracker.link`. +3. **Issue with a folder:** on a branch off `origin/main`, create `04-ISSUES/NNN-short-name/00-report.md`, `NNN` being + exactly the tracker's number and `short-name` exactly the `record` passed: ```yaml --- @@ -35,13 +54,15 @@ both. --- ``` -2. Write the symptom **as observed**, in plain terms, with the evidence that it happened — - what was run, what came back, when. -3. Say why it matters beyond the instance. An issue that is only one occurrence is a knowledge + Its status stays in this frontmatter until slice 3 of to-be 53 imports the folders (ADR 0275); + `issue-tracker.move` refuses it until then. Notes and links may still go to the tracker. +4. Write the symptom **as observed**, in plain terms, with the evidence that it happened. +5. Say why it matters beyond the instance. An issue that is only one occurrence is a knowledge base entry. -4. End with open questions rather than a proposed fix. Diagnosis is a separate step. +6. End with open questions rather than a proposed fix. Diagnosis is a separate step. ## Do not - Do not name nodes, domains, addresses or paths. This repository is public. - Do not guess the owner — `located-in:` is filled by diagnosis, not by opening. +- Do not renumber a folder or reuse a number: a number never moves. diff --git a/00-META/process/03-issues.md b/00-META/process/03-issues.md index e9457a45..650fdf2e 100644 --- a/00-META/process/03-issues.md +++ b/00-META/process/03-issues.md @@ -19,14 +19,36 @@ The knowledge base already holds the operational record and is indexed on sympto folder is not a second copy of it. An issue here is a question HQ must **answer**, not an incident someone must **clear**. +## The issue tracker holds the number + +Every issue is opened in the **issue tracker**, the module `mesh-issues` holding the seat `issue-tracker` on the +control-node ([ADR 0275](../../02-DECISIONS/0275-the-mesh-numbers-and-tracks-its-issues-in-a-module-of-its-own-and-hq-keeps-only-the-narrative-of-a-design-or-governance-issue.md), +[to-be 53](../../03-DESIGN/01-to-be/53-the-issue-tracker.md)). Its number comes from one counter advanced by +compare-and-set, so two authors opening at the same moment never get the same one. **A number is never taken by +reading `main` or the open pull requests** — that is how numbers collided (issue 155: two records sharing a number +reached `main` with every check passing). A session that cannot reach the tracker takes no number and says so. + +An issue takes one of two shapes: + +- **With a folder here** — a design or governance issue, whose narrative belongs in this public record and is + reviewed in a pull request. The tracker holds its number, title, notes and links; its status stays in the folder's + frontmatter until slice 3 of to-be 53 has imported the folders and been checked, and until then the tracker's + `move` refuses it, saying its status lives in its folder. +- **Wholly in the tracker** — every other issue. Its status, owner, notes and links live in the tracker from the + start, and nothing is written here. + +No status is ever kept in two places for one issue. + ## Steps -1. Take the next free number — **across `main` and every open pull request**, not `main` alone. - Work sits on unmerged branches for days, so two people both reading `main` allocate the same - number; it happened twice in one hour between two machines, and the second collision reached - `main` with every check passing (issue 155). `cycle.py` now refuses two records sharing a number, - which catches a collision but does not prevent one. Create - `04-ISSUES/NNN-short-name/00-report.md`: +1. Open the issue in the tracker, through the mesh MCP server: + `mesh_call issue-tracker.open` with `title`, `report` (the symptom **as observed**, in plain terms, with the + evidence that it happened), optionally `located-in` (entries of the tracker's registered list of owners), and, for + an issue that gets a folder here, `record` — the folder's name without its number, `short-name`. The tracker + answers with the number `NNN`; a refused open spends none. + + **An issue with a folder** then creates `04-ISSUES/NNN-short-name/00-report.md` under exactly that number, on a + branch: ```yaml --- @@ -38,15 +60,21 @@ incident someone must **clear**. --- ``` - Then the symptom **as observed**, in plain terms, with the evidence that it happened. -2. Investigate in `01-diagnosis.md` in the same folder — the trail, dated, including what was - ruled out. Move `status:` to `diagnosing`, then `located` once the owner is known. -3. Resolve. Set `status: resolved`, fill `fixed-by:`, and if the root cause was a design gap, + Then the symptom as observed, as in the tracker's report. + + **An issue wholly in the tracker** is done at this step: what follows happens through the tracker's verbs. +2. Investigate. For a folder-backed issue, the trail goes in `01-diagnosis.md` in the same folder — dated, + including what was ruled out — and `status:` moves to `diagnosing`, then `located` once the owner is known. For an + issue wholly in the tracker, the trail goes in `issue-tracker.note` and the status changes through + `issue-tracker.move`, which refuses `located` without a registered owner in `located-in`. +3. Resolve. Set `status: resolved` (in the frontmatter, or through `issue-tracker.move` for an issue wholly in the + tracker), fill `fixed-by:`, and if the root cause was a design gap, run playbook [02](02-graduation.md) and fill `amended-design:`. **A core issue** — its `located-in` names the controller, the node-engine, the tool runner, the SDK, or the catalogue's bus, forge or build agent — resolves with `replay:`, the id of its replay in mesh-lab's replays register, proved to fail on the commit before the fix and pass on it, or with `replay-none:` saying why none is possible - ([ADR 0237](../../02-DECISIONS/0237-a-change-is-judged-against-the-mesh-that-runs-before-it-merges-on-the-build-seat.md); `cycle.py` checks it). + ([ADR 0237](../../02-DECISIONS/0237-a-change-is-judged-against-the-mesh-that-runs-before-it-merges-on-the-build-seat.md); + `cycle.py` checks it on a folder, and `issue-tracker.move` refuses the move without it). ## Rules @@ -57,8 +85,9 @@ incident someone must **clear**. - A fix that turns out to have broken something else is written back into the record that asked for it, pointing at the new issue. Somebody arriving at a record to learn why the code is the way it is must not have to already know there was a sequel. -- Renumbering a collision happens once, in the branch that lands last. Renumbering a branch whose - author is still pushing only moves the race. +- A number never moves. A folder carries the number the tracker gave; a folder whose number collides with + another (one numbered before the tracker, or by hand) is a fault, and `cycle.py` refuses two records + sharing a number. - An issue whose answer is a general lesson should also be written to the knowledge base, so the next person searching a symptom finds it. Both, not either. - `status: wontfix` is legitimate and requires a sentence saying why. diff --git a/01-RESEARCH/042-the-mesh-keeps-its-own-issues/01-findings.md b/01-RESEARCH/042-the-mesh-keeps-its-own-issues/01-findings.md index c35e210e..e14351a7 100644 --- a/01-RESEARCH/042-the-mesh-keeps-its-own-issues/01-findings.md +++ b/01-RESEARCH/042-the-mesh-keeps-its-own-issues/01-findings.md @@ -73,6 +73,14 @@ read to the state interface (small, and every module with a counter gains it), o instance and number inside it. **Recommended: the first.** One instance is also right for v1, but the counter should not depend on it. +> **Correction — 2026-10-10.** The finding above is wrong about the SDK. Version v0.1.9, the one read, had no +> compare-and-set, but the SDK's Go state interface already had it from go/v0.1.10: `Create` (writes a key only if it +> does not exist) and `Update` (writes only at the revision the caller read), with the runtime's matching state +> verbs, both from [ADR 0259](../../02-DECISIONS/0259-an-ask-is-a-message-on-the-bus-any-channel-answers-it-and-the-asker-acts-on-a-warrant.md). +> What the tracker's counter needed and slice 1 added is `Increment`, in go/v0.1.12, which reads a counter and writes +> the next number with `Create` or `Update` at the revision it read, retrying a bounded number of times. The +> recommendation stands; the work it named was smaller than stated. ADR 0275 carries the same correction. + **Explicitly left out of v1:** decision and research numbers (slice 2), any change to playbook 03 or the hq checks (slice 2), duplicate finding beyond links (slice 3), opening an issue from a condition (slice 4), a web view (slice 5), full-text or semantic search, priorities, claims, notifications, and 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 82ab640a..ed8095c9 100644 --- a/03-DESIGN/01-to-be/53-the-issue-tracker.md +++ b/03-DESIGN/01-to-be/53-the-issue-tracker.md @@ -1,7 +1,7 @@ --- layer: to-be status: in-progress -code: [mesh-catalog, mesh-sdk] +code: [mesh-catalog modules/mesh-issues, mesh-sdk] updated: 2026-10-10 decisions: - 02-DECISIONS/0275-the-mesh-numbers-and-tracks-its-issues-in-a-module-of-its-own-and-hq-keeps-only-the-narrative-of-a-design-or-governance-issue.md