Merge pull request 'ADR 0283: an agent moves an issue to fixing under its own name, and an issue is resolved only from fixing (issue 399)' (#295) from feat/399-fixing-status into main

This commit was merged in pull request #295.
This commit is contained in:
2026-10-10 19:13:24 +00:00
8 changed files with 243 additions and 23 deletions
+4 -2
View File
@@ -24,14 +24,16 @@ result is not "nothing to learn" — it is the reason the next person repeats th
## Steps
1. Read the issue: `mesh_call issue-tracker.get` with its number, and `00-report.md` when it has a
folder. Move it to `diagnosing` with `issue-tracker.move`.
folder. Before you start, move it to `diagnosing` with `issue-tracker.move` and `by`, your name and node as
who@node (such as `fix-399@laptop`). The tracker refuses it while another worker is current, naming them.
2. Investigate. The trail goes in `issue-tracker.note`, **dated** in its text, including what was
ruled out and how; for an issue with a folder, in `01-diagnosis.md` there as well. Archaeology —
which commit, which pull request, which date a behaviour changed — is the most valuable content.
3. When the owner is known, `issue-tracker.move` to `located` with `located-in`: entries of the
tracker's registered list of owners (repositories, and modules as `mesh-catalog modules/<module>`);
the tracker refuses an owner it does not know.
4. On resolution: `issue-tracker.move` to `resolved` with `fixed-by`, and `replay` or `replay-none`
4. Before you start the fix: `issue-tracker.move` to `fixing` with `by`.
5. On resolution: `issue-tracker.move` to `resolved`, taken only from `fixing`, with `fixed-by`, and `replay` or `replay-none`
for a core issue. If the root cause was a design gap, run `hq-graduate` for the amendment and give
`amended-design`. Nothing of this is written in the report's frontmatter.
+1 -1
View File
@@ -16,7 +16,7 @@ generated on demand and never written back to disk.
| Research | `01-RESEARCH/NNN-*/00-overview.md` | `status` (`active` / `graduated` / `abandoned`), `initiated`, `touches`, `became` |
| Design | `03-DESIGN/**/*.md` (not READMEs) | `layer` (`as-is` / `to-be`), `status` (`designed` / `in-progress` / `implemented` / `abandoned`), `code`, `updated`, `decisions` |
| Decisions | `02-DECISIONS/NNNN-*.md` | `status` (`proposed` / `accepted` / `superseded`), `date`, `deciders`, `reconstructed`, `superseded-by`, `extends` |
| Issues | the issue tracker, not a file: `mesh_call issue-tracker.list` (optionally `status`, `owner`, `phrase`) and `issue-tracker.get` | `status` (`open` / `diagnosing` / `located` / `resolved` / `wontfix`), `opened`, `located-in`, `fixed-by`, `amended-design`, `record` (the folder here, when it has one) |
| Issues | the issue tracker, not a file: `mesh_call issue-tracker.list` (optionally `status`, `owner`, `phrase`) and `issue-tracker.get` | `status` (`open` / `diagnosing` / `located` / `fixing` / `resolved` / `wontfix`), `worker` and `stale` while `diagnosing` or `fixing`, `opened`, `located-in`, `fixed-by`, `amended-design`, `record` (the folder here, when it has one) |
## Steps
+6 -1
View File
@@ -551,7 +551,7 @@ asking, never the act. **Decided by** ADR 0152, 0175, 0234, 0259, 0272.
## The record — how this repository works
Not a domain of the mesh but of the way it is built, listed because its words meet the mesh's.
**Recorded in** this repository and the issue tracker. **Decided by** ADR 0019, 0080, 0244, 0275.
**Recorded in** this repository and the issue tracker. **Decided by** ADR 0019, 0080, 0244, 0275, 0283.
- **research effort**, **graduation**, **hand-off**, **playbook** — an investigation in `01-RESEARCH/`;
its closing into a decision and a design; a design given to a code repository; a documented workflow
@@ -576,6 +576,11 @@ Not a domain of the mesh but of the way it is built, listed because its words me
duplicate (the **duplicate check**), its **severity** and what it **needs**, a suggested owner, and the issues it
depends on or relates to; it fills only what nobody gave ([ADR 0279](../02-DECISIONS/0279-the-issue-tracker-triages-every-new-issue-and-an-issue-is-ready-when-what-it-depends-on-is-delivered.md)).
- **ready** — of an issue: every issue it depends on is wontfix, or resolved with its fix delivered.
- **worker** — of an issue: the agent or person, with its node (who@node), that moved it to `diagnosing` or `fixing`
and works on it; another is refused while the worker is current, unless it gives a reason to **take it over**. A
worker with nothing done on the issue for a day is **stale**. **Fixing** is the status an issue is at while its fix
is worked on; an issue is resolved only from it ([ADR 0283](../02-DECISIONS/0283-an-agent-moves-an-issue-to-fixing-under-its-own-name-and-an-issue-is-resolved-only-from-fixing.md)).
Not a *claim* or a *holder*, which are a module's on a seat.
- **hq check** — one of `00-META/checks/`, run by `merge-check.sh` as this repository's check.
## Homonyms
+19 -6
View File
@@ -71,10 +71,20 @@ import read, which every imported issue names (`imported.commit` in `issue-track
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,
2. Investigate. **Before you start, move the issue to `diagnosing` with `by`**: who works on it and its node, as
who@node (`fix-399@laptop`, `operator@workstation`). The tracker keeps you as the issue's **worker**, and `get` and `list`
show it with since when. 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. A note keeps you the worker; a
worker with nothing done on the issue for a day is stale. Then move it to `located` with `located-in`, which the
tracker refuses without a registered owner; that ends your work on it.
3. Fix. **Before you start the fix, move the issue to `fixing` with `by`**, even when you diagnosed it yourself. The
tracker refuses the move while another worker is current, naming them: ask them, or take it over with
`take-over` saying why, which is noted on the issue. A stale worker may be taken over from without a reason.
Name the fix in `fixed-by` when it merges, with a move to `fixing` that gives `by` again; the issue stays
`fixing` until the acceptance is proven live
([ADR 0283](../../02-DECISIONS/0283-an-agent-moves-an-issue-to-fixing-under-its-own-name-and-an-issue-is-resolved-only-from-fixing.md),
[ADR 0281](../../02-DECISIONS/0281-an-issue-knows-whether-its-fix-is-delivered-and-a-fix-stuck-after-its-merge-is-loud.md)).
4. Resolve. `issue-tracker.move` to `resolved`, which the tracker takes only from `fixing`, 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
@@ -97,8 +107,11 @@ import read, which every imported issue names (`imported.commit` in `issue-track
- 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
- **An agent says when it starts work on an issue**, by moving it to `diagnosing` or `fixing` with `by`. Two agents
never start the same work without knowing: the second is refused, naming the first.
- **A rule states how it is checked.** The cycle's rules on an issue — a status one of the six, `diagnosing` and
`fixing` with a worker and no other current one, `located` with an owner, `resolved` only from `fixing` and 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.
@@ -116,6 +116,13 @@ along the way".
`resolved` need `located-in`; `resolved` needs `fixed-by`; a core issue resolves with `replay` or `replay-none`
([ADR 0237](0237-a-change-is-judged-against-the-mesh-that-runs-before-it-merges-on-the-build-seat.md));
`wontfix` needs a reason. `located-in` names an entry of a registered list of repositories and modules.
> **The mechanism changed — 2026-10-10, by [ADR 0283](0283-an-agent-moves-an-issue-to-fixing-under-its-own-name-and-an-issue-is-resolved-only-from-fixing.md).**
> What still stands: the cycle's rules are enforced at the write, and §5 for who acted. What moved: there are six
> statuses, `fixing` between `located` and `resolved`; a move to `diagnosing` or `fixing` names the issue's worker
> in `by`, which is not the actor of §5 but who works on it as they state it; and `resolved` is reached only from
> `fixing`.
7. **The word is *issue*.** The module is the *issue tracker*, named `issues`; *ticketing system* is retired in the
glossary, and the bare word *ticket* is a homonym that never means an issue.
8. **It is built in slices, each ending at something the operator sees.** Slice 1 is the module with `open`, `get`,
@@ -84,6 +84,11 @@ therefore name a fix in `fixed-by` when it merges, with the issue still `located
`move` to the status an issue already has is taken when it changes what the issue holds, such as its `fixed-by`, and
refused when it changes nothing. `move` still requires `fixed-by` to resolve.
> **The mechanism changed — 2026-10-10, by [ADR 0283](0283-an-agent-moves-an-issue-to-fixing-under-its-own-name-and-an-issue-is-resolved-only-from-fixing.md).**
> What still stands: delivered is not resolved, and an issue is resolved after the proof. What moved: the fix is
> named while the issue stays `fixing`, not `located`, because an issue is resolved only from `fixing`, and a move
> to `fixing` names its worker in `by`.
### 4. A stuck fix is loud
A fix merged and not delivered after **two hours** (the module's setting `stuck-after`) is said once: a note on the
@@ -0,0 +1,169 @@
---
topic: how we work
status: accepted
date: 2026-10-10
deciders: jochen
reconstructed: false
extends: 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
---
# 283. An agent moves an issue to fixing under its own name, and an issue is resolved only from fixing
## Context
On 2026-10-10 the operator asked that an agent say when it starts work on an issue, and chose the word for the
status it moves the issue to: **fixing**. The statuses become open → diagnosing → located → fixing → resolved, or
wontfix.
**What the tracker holds, measured on 2026-10-10** (`issue-tracker.list`): 43 issues at `open`, 1 at `diagnosing`,
51 at `located`. Nothing on an issue says who works on it. Two agents can start on the same issue and neither sees
the other. Every move is recorded as by `unproven`: the runtime does not hand a module the identity of its caller
(issue 340), so [ADR 0275](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)
§5 ("the caller is the bus credential, never an argument") records nobody in particular. And an issue moves to
`resolved` from any status, so nothing shows that anyone said they started the fix before it was resolved.
[To-be 53](../03-DESIGN/01-to-be/53-the-issue-tracker.md) names "claims" under *What it leaves out*, as needing a
decision of its own. This is that decision. The glossary already uses *claim* for a module taking a spot on a seat,
and *holder* for the module that holds a seat, so neither names the person or agent working on an issue. The
glossary has no word for that; this record proposes **worker**, added to the glossary in the same change.
The record was searched first ("claim", "who works on", "assignee", "fixing", "take over"): to-be 53's *What it
leaves out*, ADR 0275 §5 and §6, and [ADR 0281](0281-an-issue-knows-whether-its-fix-is-delivered-and-a-fix-stuck-after-its-merge-is-loud.md)
§3, which has an agent name a fix while the issue stays `located`.
## Considered Options
### How the worker is named
1. *The caller's identity, as the runtime proves it.* Not possible as the mesh stands: the runtime does not say who
called (issue 340). When it does, a node's credential is shared by every session on that node, so two agents on
one machine would still read as one.
2. **`by`, given by the worker on the move, as who@node.** Chosen. The worker states its own name. ADR 0275 §5
still holds for *who acted*: the tracker keeps recording that from the runtime, never from an argument. `by` names
who works on the issue, which is a different fact. Because a worker names itself, the refusal below lets honest
workers see each other; it does not stop a worker that gives a false name.
3. *An assignee, set by the operator or the triage.* Refused. Nobody hands out work: agents choose it from `list`,
and the triage estimates and does not decide.
### What a second worker meets
1. *Nothing: both are shown.* Refused. Two agents starting the same fix without knowing is what this record prevents.
2. **A refusal naming the worker, unless the move says why it takes the issue over; the reason is noted.** Chosen.
3. *A refusal with no way past it until the worker moves on.* Refused. An agent whose session ended would keep the
issue forever.
### When a worker counts as gone
1. *A fixed time after the worker started.* Refused. A long fix that keeps writing notes would lose its issue.
2. **A time with nothing done on the issue: no move, note, link or set by a caller.** Chosen. The tracker's own
writes (the triage, the duplicate check, the delivery's notes) do not count, because they say nothing about
whether the worker is still there.
### What may be resolved
1. *Any issue with a fix named, as today.* Refused. Nothing shows that anyone started the fix.
2. **Only an issue at `fixing`.** Chosen. This is the check that the agent rule holds: to resolve an issue, someone
must first have moved it to `fixing` under their own name.
## Decision
### 1. Six statuses
An issue is `open`, `diagnosing`, `located`, `fixing`, `resolved` or `wontfix`. **Fixing** means someone works on its
fix. `wontfix` is unchanged: it is reached from any status, with a reason.
### 2. A move to diagnosing or fixing names its worker
A move to `diagnosing` or `fixing` needs `by`: the issue's **worker**, the agent or person who works on it and the
node it works on, written as who@node (`fix-399@laptop`, `operator@workstation`). These are the limits:
- `who` is letters, digits and `.`, `_`, `/`, `-`;
- `node` is lower-case letters, digits and `-`;
- the whole is at most 120 bytes and is kept in lower case;
- it is refused when it has the shape of a secret, like any field of an issue.
The issue keeps its worker (`by`, `since`, and `active`, the last time a caller did anything on it) while it stays
at `diagnosing` or `fixing`. A move to any other status ends the work. The same worker moving the issue from
`diagnosing` to `fixing` keeps its `since`. A move to `fixing` that names a fix while the issue stays `fixing` is a
move to `fixing` too, and needs `by`. `by` on a move to any other status is refused. `get` shows the worker, and
each row of `list` shows `worker`, `since` and `stale`.
### 3. Another worker is refused while the worker is current
A move to `diagnosing` or `fixing` by a different worker is refused while the worker is current. The refusal names
the worker, since when it has worked on the issue, and when it was last active. A move that gives `take-over` with a
reason takes the issue over, and a note on the issue says who took it from whom and why. `take-over` is refused
when nobody else works on the issue, and on a move to a status that has no worker.
### 4. A worker who did nothing for a day is stale
A worker with no move, note, link or set by a caller on the issue for `worker-stale-after` (a setting of the module,
**24 hours** by default) is **stale**. `list` says `stale`, `get` says `worker-stale`, and another worker may take the
issue over without a reason; the take-over is still noted. 24 hours is a working day and a night. An agent whose
session ended, or whose machine is asleep, frees the issue by the next day. An agent that is still working keeps it
by noting what it found, which playbook 03 already asks for.
### 5. Resolved is reached only from fixing
A move to `resolved` is refused unless the issue is at `fixing`. An issue already resolved may still have what it
holds corrected. The other rules for `resolved` (`located-in`, `fixed-by`, and a replay for a core issue) are
unchanged.
### 6. The event and the reads carry the worker
The `moved` event carries:
- `by`: the worker, when the move names one; who acted, for a move that names none;
- `since`: when the worker started;
- `caller`: who acted, as the runtime proves it (`unproven` today);
- `took-over-from` and `take-over`: on a take-over;
- `released`: the worker whose work the move ended.
`get` carries `worker` and `worker-stale`. Another module can read who works on an issue from either. No event
carries a secret, because `by` and the take-over reason are refused when they have the shape of one.
### 7. Fixing is not closed
The duplicate check, the triage, readiness and the ready-to-verify note treat `fixing` like `diagnosing` and
`located`. A fix is named in `fixed-by` while the issue stays at `fixing`, and the issue is resolved after the proof
(ADR 0281 §3, which said `located`).
### 8. Agents say when they start
An agent moves an issue to `diagnosing` or `fixing` with `by` before it starts work on it. Playbook 03 says so. The
rule for every session is proposed through the agent module's shared instructions and taken on the operator's
warrant ([ADR 0274](0274-an-agent-proposes-a-shared-instruction-section-and-every-node-takes-it-only-on-the-operators-warrant-which-it-proves-itself.md)).
## Consequences
- `list` shows who works on what and since when. A second agent learns of the first before it starts, not after
both have opened pull requests.
- Each of the 51 issues at `located` now goes through `fixing` before it is resolved. An agent that resolves one
names itself first.
- `by` is what the worker says it is. A false name passes, and the tracker cannot tell. The proven caller is
tracked by issue 340.
- A worker that stops without moving the issue on keeps others out for up to 24 hours, unless they give a reason.
The reason is on the issue for the operator to read.
- The next step is that an alert names the issue tracking its condition and that issue's state in plain words, such
as "an agent on the laptop is fixing it since 21:10". That needs a link from an issue to a condition key or kind, and is
tracked by issue 400. This record makes the worker readable for it, from `get` and from the `moved` event.
## How it is checked
| Rule | Checked by |
|---|---|
| A move to diagnosing or fixing names its worker as who@node; `by` or `take-over` on another status is refused; a `by` with a secret's shape is refused | the tracker's table test over the cycle's rules (mesh-catalog `modules/mesh-issues`), one row per refusal, each refused row changing nothing and saying no event |
| Another worker is refused while the worker is current, naming the worker | the tracker's test of a second worker at `diagnosing` and at `fixing`, 23 hours after the first: refused, the issue unchanged, no event |
| A take-over gives a reason, which is noted; the event says from whom | the tracker's take-over test: the note, the worker, and `took-over-from` and `take-over` on the `moved` event |
| A stale worker is shown and may be taken over from without a reason; a caller's note keeps the worker current, the tracker's own note does not; the bound is the setting | the tracker's stale-worker tests, with a clock the test moves |
| **Resolved only from fixing.** This is the check that the agent rule holds: no issue is resolved unless someone first moved it to `fixing` under their own name | the table test's rows resolving from `open`, `located` and `diagnosing`, each refused; live, a resolve of an issue at `located` is refused |
| Fixing is not closed | the tracker's test that every status but `resolved` and `wontfix` is offered to the triage |
| Live | an agent moves its issue to `fixing` with `by`, and `get` and `list` show the worker with since; a resolve of an issue at `located` is refused, naming the rule |
## References
- [ADR 0275](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): the tracker and its rules, which this record extends
- [ADR 0281](0281-an-issue-knows-whether-its-fix-is-delivered-and-a-fix-stuck-after-its-merge-is-loud.md): delivered is not resolved; the fix is now named while the issue is `fixing`
- [ADR 0274](0274-an-agent-proposes-a-shared-instruction-section-and-every-node-takes-it-only-on-the-operators-warrant-which-it-proves-itself.md): how the rule for every session is taken
- [To-be 53](../03-DESIGN/01-to-be/53-the-issue-tracker.md): the design this record amends
- Playbook [03 — issues](../00-META/process/03-issues.md)
+32 -13
View File
@@ -8,6 +8,7 @@ decisions:
- 02-DECISIONS/0278-the-issue-tracker-checks-every-new-issue-for-a-duplicate-through-a-judgement-the-agent-makes-without-tools.md
- 02-DECISIONS/0279-the-issue-tracker-triages-every-new-issue-and-an-issue-is-ready-when-what-it-depends-on-is-delivered.md
- 02-DECISIONS/0281-an-issue-knows-whether-its-fix-is-delivered-and-a-fix-stuck-after-its-merge-is-loud.md
- 02-DECISIONS/0283-an-agent-moves-an-issue-to-fixing-under-its-own-name-and-an-issue-is-resolved-only-from-fixing.md
---
# 53 — The issue tracker
@@ -68,8 +69,8 @@ agent finds them with `mesh_search` ("open an issue") and calls them as `issue-t
|---|---|---|
| `open` | a title, the report as text, optionally `located-in` and a folder path | checks the issue, then takes the next number and writes it; returns the number. Refuses an empty title or report, and an owner not on the registered list |
| `get` | a number | the issue whole: fields, notes, links |
| `list` | optionally a status, an owner, a phrase | compact rows, newest first, short enough to read in a chat: number, status, owner, title |
| `move` | a number, a status, and what that status needs | changes the status under the rules of § 5 |
| `list` | optionally a status, an owner, a phrase | compact rows, newest first, short enough to read in a chat: number, status, owner, title, and the worker with since and whether it is stale |
| `move` | a number, a status, and what that status needs; `by` for `diagnosing` and `fixing`, and `take-over` with a reason to take an issue over from another worker | changes the status under the rules of § 5 |
| `note` | a number and a text | appends to the issue's notes; a note is never edited |
| `link` | a number, a kind and a target, or `remove` | adds or removes a typed link |
| `set` | a number and any of `severity`, `needs`, `suggested-owner` | changes them as a person decides (§ 10) |
@@ -80,11 +81,16 @@ Each verb's description says in plain words what it does and what it refuses, wi
an agent picks the right one from `mesh_search` alone. A refusal says what was wrong and what would be accepted.
**The caller is the bus credential, never an argument.** The runtime hands the module the identity of each call's
caller; the module records that identity as who acted. No verb takes an actor.
caller; the module records that identity as who acted. No verb takes an actor. `by` on `move` is not one: it names
the issue's worker, who works on it, as the worker states it
([ADR 0283](../../02-DECISIONS/0283-an-agent-moves-an-issue-to-fixing-under-its-own-name-and-an-issue-is-resolved-only-from-fixing.md)).
## 3. What one issue holds
- `number` (its key), `title`, `status` (`open`, `diagnosing`, `located`, `resolved`, `wontfix`), `opened`, `closed`;
- `number` (its key), `title`, `status` (`open`, `diagnosing`, `located`, `fixing`, `resolved`, `wontfix`), `opened`,
`closed`;
- `worker`, while it is `diagnosing` or `fixing`: who works on it as who@node, `since` when, and `active`, the last
time a caller did anything on it (§ 5);
- `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;
@@ -137,7 +143,9 @@ at the moment the module is switched on. Numbers already skipped stay unused, an
**Every change is an event the module declares** under `emits`
([ADR 0041](../../02-DECISIONS/0041-events-are-a-relationship.md)): `opened`, `moved`, `noted`, `linked`. Each carries
the number, what changed, and who changed it, so the events are the audit trail, and anything watching the bucket or
the events sees a change as it happens. No event carries a secret, and an issue holds none.
the events sees a change as it happens. `moved` also carries the worker a move names, as `by`, with `since`, and who
acted as `caller`; on a take-over `took-over-from` and the reason, and `released` when a move ends the work. No
event carries a secret, and an issue holds none.
## 5. The cycle's rules, at the write
@@ -145,13 +153,17 @@ the events sees a change as it happens. No event carries a secret, and an issue
| The issue moves to | Needs |
|---|---|
| any status | one of the five |
| any status | one of the six |
| `diagnosing` or `fixing` | `by`, the worker as who@node; refused while another worker is current, naming them, unless `take-over` gives a reason, which is noted; a worker with nothing done on the issue for `worker-stale-after` (24 hours) is stale and may be taken over from without one |
| any other status | no `by` and no `take-over`; the move ends the work |
| `located` | `located-in` names at least one registered owner |
| `resolved` | `located-in`, and `fixed-by` saying what fixed it |
| `resolved` | the issue is at `fixing` (or already `resolved`, to correct what it holds); `located-in`, and `fixed-by` saying what fixed it |
| `resolved`, for 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) | `replay` (an id from mesh-lab's replays register) or `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)) |
| `wontfix` | a reason |
A refused move changes nothing and says which rule refused it. `cycle.py` checked the folders that carried status until
A refused move changes nothing and says which rule refused it. The rows for `diagnosing`, `fixing` and `resolved` are
[ADR 0283](../../02-DECISIONS/0283-an-agent-moves-an-issue-to-fixing-under-its-own-name-and-an-issue-is-resolved-only-from-fixing.md)'s:
resolved only from `fixing` is the check that an agent said it started the fix. `cycle.py` checked the folders that carried status until
slice 3; since then it refuses a status key in any report, and judges no issue's status.
## 6. How the operator and agents use it
@@ -161,6 +173,11 @@ or governance issue, writes `04-ISSUES/NNN-slug/` under it with the number in th
changes to that the day slice 1 is live; nothing else in playbook 03 changes in slice 1. `list` answers "what is open"
in one call, from any session, and the responder on a channel answers from it once the seat exists.
**An agent says when it starts.** Before it starts work on an issue, an agent moves it to `diagnosing` (to find where
it lives) or `fixing` (to fix it) with `by`, its own name and node. `list` then shows who works on what, and a second
agent is refused before it starts the same work. An agent that keeps working notes what it finds, which keeps it the
worker; one that stops moves the issue on, or is stale a day later.
## 7. How it is checked
| Rule | Checked by |
@@ -171,6 +188,7 @@ in one call, from any session, and the responder on a channel answers from it on
| The cycle's rules hold at the write | the module's table test over § 5, one case per row, each refused case changing nothing |
| The module creates no bucket | the runtime refuses a module that tries (ADR 0201 §3); the controller's raise asserts both buckets |
| The caller is who acted | the module's test that the recorded actor is the call's identity, whatever the arguments say |
| A worker is named on a move to diagnosing or fixing, another is refused while it is current, a take-over is noted, a stale one may be taken over from, and resolved is reached only from fixing | the rows of [ADR 0283](../../02-DECISIONS/0283-an-agent-moves-an-issue-to-fixing-under-its-own-name-and-an-issue-is-resolved-only-from-fixing.md)'s "How it is checked" |
| An issue's delivery line follows the delivery; ready to verify once; a stuck fix said once and cleared | the rows of [ADR 0281](../../02-DECISIONS/0281-an-issue-knows-whether-its-fix-is-delivered-and-a-fix-stuck-after-its-merge-is-loud.md)'s "How it is checked" |
| 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](../../02-DECISIONS/0279-the-issue-tracker-triages-every-new-issue-and-an-issue-is-ready-when-what-it-depends-on-is-delivered.md)'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](../../02-DECISIONS/0278-the-issue-tracker-checks-every-new-issue-for-a-duplicate-through-a-judgement-the-agent-makes-without-tools.md)'s "How it is checked" |
@@ -195,7 +213,7 @@ within a few minutes, keeping its report on the older one; an issue that repeats
was checked** ([ADR 0278](../../02-DECISIONS/0278-the-issue-tracker-checks-every-new-issue-for-a-duplicate-through-a-judgement-the-agent-makes-without-tools.md)).
- **Started by the tracker's own `opened` event**, which the module consumes. Only an issue still at `open` is
checked, against every older issue at `open`, `diagnosing` or `located`; resolved and wontfix issues are never
checked, against every older issue at `open`, `diagnosing`, `located` or `fixing`; resolved and wontfix issues are never
offered or changed.
- **Judged in two questions** to the agent module's `claude_code_judge` on the tracker's node: a shortlist of at
most five by titles, then a verdict on the reports (`duplicate`, `related` or `none`, whether it is certain,
@@ -249,13 +267,14 @@ stuck after its merge is said** ([ADR 0281](../../02-DECISIONS/0281-an-issue-kno
- `get` and each row of `list` carry **delivery**, one line: "fix not delivered: …", "held: …", "fix merged, not
delivered", "fix not merged", "nothing heard …", "delivered to every machine it should reach".
- When every fix of an issue not yet resolved is delivered, it gains a note and the event `ready-to-verify`, once;
it is resolved after the acceptance is proven live. A fix is named while the issue stays `located`: `move` to the
same status changes what the issue holds.
it is resolved after the acceptance is proven live. A fix is named while the issue stays `fixing`: `move` to the
same status, with `by`, changes what the issue holds.
- A fix merged and not delivered after `stuck-after` (two hours) is said once: a note on the issue and a warning on
the operator's channel, cleared when it is delivered. It is not a controller condition: a module that runs only
its bundle cannot raise one.
## What it leaves out
Priorities beyond severity, claims, 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:
none of them is in any slice above, and each needs a decision of its own.
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:
none of them is in any slice above, and each needs a decision of its own. Who works on an issue, listed here until
2026-10-10, is settled by [ADR 0283](../../02-DECISIONS/0283-an-agent-moves-an-issue-to-fixing-under-its-own-name-and-an-issue-is-resolved-only-from-fixing.md).