The import of slice 3 (ADR 0275) was checked against every folder: no report changed since the commit it read, and the tracker holds each report's status, owner, fix, design amendment, replay and closing day. The keys are removed from all 361 reports, cycle.py refuses them in any report, and the playbooks, skills and READMEs that still pointed at them name the tracker instead.
105 lines
6.8 KiB
Markdown
105 lines
6.8 KiB
Markdown
# Playbook 03 — Issues
|
|
|
|
**Trigger.** Something is wrong at the level of the mesh's design or governance — a rule that
|
|
turns out to be unenforced, a stated behaviour that does not happen, a silent failure the
|
|
design permits.
|
|
|
|
**Who runs it.** Anyone may open an issue. No localisation is required to report one.
|
|
|
|
## What belongs here, and what does not
|
|
|
|
| Belongs in `04-ISSUES` | Belongs in the knowledge base |
|
|
|---|---|
|
|
| The design permits a failure to be silent | How to fix one occurrence of it |
|
|
| A documented rule is enforced by nothing | A command that works around it |
|
|
| A stated invariant is false in practice | A node-specific quirk |
|
|
| The owning component is unknown and finding it needs the whole mesh in view | Symptom → fix, once the answer is known |
|
|
|
|
The knowledge base already holds the operational record and is indexed on symptoms. This
|
|
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 and the status
|
|
|
|
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.
|
|
|
|
**The tracker is the truth for every issue's status, owner, fix and links**, whether or not the issue has a folder
|
|
here. `issue-tracker.get NNN` says where an issue stands; `issue-tracker.list` says what is open. Nothing here
|
|
says it: a report's frontmatter carries no status.
|
|
|
|
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 folder holds the report and the diagnosis; the tracker holds everything else.
|
|
- **Wholly in the tracker** — every other issue. Nothing is written here.
|
|
|
|
**`04-ISSUES/` stays, for the narrative only.** It keeps the public narrative of a design or governance issue: the
|
|
symptom as observed, the diagnosis, what was ruled out, and why. A plain bug — a defect whose fix needs no design
|
|
question answered — needs no folder; it is whole in the tracker.
|
|
|
|
**The reports written before the tracker** (the folders numbered 001 to 364) carried `status:`, `located-in:`,
|
|
`fixed-by:`, `amended-design:`, `replay:` and `replay-none:` in their frontmatter until the import of slice 3 had
|
|
taken them into the tracker and been checked against it, field by field; then one pull request removed them, so
|
|
that no status is held in two places. What they said that day is in this repository's history at the commit the
|
|
import read, which every imported issue names (`imported.commit` in `issue-tracker.get`).
|
|
|
|
## Steps
|
|
|
|
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
|
|
---
|
|
opened: YYYY-MM-DD
|
|
---
|
|
```
|
|
|
|
Then `# NNN. The title`, the title as the tracker holds it, and the symptom as observed, as in the tracker's
|
|
report. **No status key**: `cycle.py` refuses `status:`, `located-in:`, `fixed-by:`, `amended-design:`,
|
|
`replay:` or `replay-none:` in any report, because the tracker holds them and two places holding one fact
|
|
drift.
|
|
|
|
**An issue wholly in the tracker** is done at this step.
|
|
2. Investigate. The trail goes in `issue-tracker.note`, and, for a folder-backed issue, in `01-diagnosis.md` in the
|
|
same folder as well — dated, including what was ruled out. The status moves through `issue-tracker.move`:
|
|
to `diagnosing`, then to `located` with `located-in`, which the tracker refuses without a registered owner.
|
|
3. Resolve. `issue-tracker.move` to `resolved` with `fixed-by`, and, if the root cause was a design gap,
|
|
run playbook [02](02-graduation.md) and give `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));
|
|
`issue-tracker.move` refuses the move without it. `wontfix` needs a `reason`.
|
|
|
|
## Rules
|
|
|
|
- Closed issues are never deleted — they are the mesh's symptom-to-component memory.
|
|
- `fixed-by` names something that will still exist: a commit or a pull request, never a branch. A
|
|
branch is deleted when it merges, so a branch name there is a pointer that resolves to nothing by
|
|
the time anybody follows it.
|
|
- 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.
|
|
- 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.
|
|
- `wontfix` is legitimate and requires a sentence saying why; the tracker refuses it without one.
|
|
- **A rule states how it is checked.** The cycle's rules on an issue — a status one of the five, `located` with an
|
|
owner, `resolved` with a fix, a core issue with its replay, `wontfix` with a reason — are refused at the write by
|
|
`issue-tracker.move` (mesh-catalog `modules/mesh-issues`, its table test over the rules). `cycle.py` checks what
|
|
this repository still holds: no two folders share a number, every report has frontmatter with the day it was
|
|
`opened:`, and no report carries a status key.
|