mesh/merge-gate pass: builds 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 delivered
An open's lost answer is judged by the issue's first entry; an entry that does not fold faults its issue on start; a value written beside the log is never folded over; one issue is kept in at most 252 KiB so its whole operation fits a log entry.
381 lines
31 KiB
Markdown
381 lines
31 KiB
Markdown
# mesh-issues
|
|
|
|
The issue tracker: the mesh numbers and tracks its issues in a module of its own (novox/hq ADR 0275,
|
|
to-be 53). An **issue** is a question about the mesh that someone must answer; this module holds the
|
|
mesh's issues and hands out their numbers, and the numbers of decision and research records too (ADR
|
|
0275 rule 8, ADR 0290 rule 5). It holds the seat `issue-tracker`, once for the mesh, on the
|
|
control-node.
|
|
|
|
Built on the model of [hits](https://github.com/impire-io/hits), a headless issue tracker on NATS, studied
|
|
at release v0.7.0: its statuses, fields, append-only notes, typed links and compare-and-set numbering are
|
|
taken as ideas. It carries none of its code, under a licence that is not an open-source one.
|
|
|
|
## Verbs
|
|
|
|
Called as `issue-tracker.<verb>` through the mesh's tools; each says in its description what it does and
|
|
what it refuses.
|
|
|
|
| verb | takes | does |
|
|
|---|---|---|
|
|
| `open` | `title`, `report`, optionally `located-in`, `record` | checks the issue, then takes the next number and keeps it under that number; answers the number |
|
|
| `get` | `number` | the issue whole: fields, notes, links |
|
|
| `list` | optionally `status`, `owner`, `phrase`, `limit`, `severity`, `needs`, `ready`, `flag` (`delivered-not-resolved` or `abandoned`), `search` (words, ranked), `before` (a number, the cursor) | short rows, newest first, or best first for a `search`: number, status, owner, title, and each flag that holds; `next`, the `before` that reads on, when more match |
|
|
| `move` | `number`, `status`, and what that status needs (`by` for `diagnosing` and `fixing`, optionally `take-over`) | changes the status under the development cycle's rules |
|
|
| `note` | `number`, `text` | appends a note; a note is never edited |
|
|
| `link` | `number`, `kind`, `target`, optionally `remove` | adds or removes a typed link |
|
|
| `import` | optionally `dry-run`, `commit` | hq's issue folders, read through the records module, each written as an issue under its own number; see below |
|
|
| `set` | `number`, any of `severity`, `needs`, `suggested-owner` | changes them as a person decides |
|
|
| `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 |
|
|
|
|
**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`,
|
|
`diagnosing`, `located`, `fixing`, `resolved`, `wontfix`; `diagnosing` and `fixing` need `by`; `located` needs
|
|
`located-in`; `resolved` is reached only from `fixing` and needs `located-in` and `fixed-by`; a core issue (located in the controller, the node-engine, the tool runner,
|
|
the SDK, or the catalogue's bus, forge or build agent) resolves with `replay` or `replay-none`; `wontfix`
|
|
needs a `reason`. A refused change changes nothing and says which rule refused it.
|
|
|
|
**Who works on it** (hq ADR 0284). A move to `diagnosing` or `fixing` names in `by` the issue's **worker**: who
|
|
works on it and its node, as `who@node` (such as `fix-399@g14` or `jochen@shanks`, kept in lower case). The issue
|
|
keeps its worker (`worker`: `by`, `since`, `active`) while it stays at either status; any other status ends the
|
|
work. `get` shows it, with `worker-stale`, and each `list` row shows `worker`, `since` and `stale`. A move to either
|
|
status by someone else while the worker is current is refused, naming the worker; with `take-over` saying why, the
|
|
issue is taken over, and the reason is noted on it. A worker with no move, note, link or set from a caller on the
|
|
issue for `worker-stale-after` (default `24h`) is stale and may be taken over from without a reason, still noted.
|
|
The tracker's own writes (the triage, the duplicate check, the delivery notes) keep no worker current. The `moved`
|
|
event carries `by` (the worker; who acted, for a move naming none), `since`, `caller` (who acted, as the runtime
|
|
proves it: see *Who acted*), and `took-over-from`, `take-over` or `released` when they apply. `by` is what the
|
|
worker says it is, not who called, so the worker lets agents and people see each other; it is not a lock against
|
|
a false name.
|
|
|
|
**An issue with a folder in hq** (`record` at open: the folder's name, without the number) is whole in the
|
|
tracker like any other: the folder holds its narrative, the tracker its status. Until the import of
|
|
slice 3 ran, such an issue kept its status in the folder and `move` refused it; the import filled it.
|
|
|
|
## The triage (hq ADR 0278, ADR 0279)
|
|
|
|
Every issue opened is triaged by the module itself: it consumes its own `mesh-issues.opened` event, and for an
|
|
issue still at `open` asks the agent on its node — `claude-code.claude_code_judge@<node>`, which runs the agent
|
|
with no tools under the node's licence — two questions: a shortlist of at most five older issues by their titles,
|
|
then, always, a judgement on the reports: whether it repeats one (`duplicate`, `related` or `none`, whether it is
|
|
certain, and why), its **severity** (critical, major, minor), what it **needs** (none, decision, operator), a
|
|
suggested owner when it names none, and the shortlisted issues it **depends on** or **relates to**, each with a
|
|
one-line reason. Only issues at `open`, `diagnosing`, `located` or `fixing` that are older than the new one are offered.
|
|
|
|
The judgement is kept on the issue (`triage`) and said as the event `triaged` before anything else, then applied
|
|
through the module's own `note`, `set`, `link` and `move`, each recorded as by `triage` and each only when not
|
|
done yet:
|
|
|
|
1. one note saying the whole judgement, a line per value with its reason; where the issuer gave a severity or
|
|
needs the triage disagrees with, the line says so and the given value stands;
|
|
2. each empty value filled — never one a person gave;
|
|
3. each `depends-on` and `relates-to` link added, unless it is there, would close a cycle, or its target is
|
|
resolved or wontfix; the older issue gains a note;
|
|
4. a certain duplicate: linked `duplicates`, its title and report noted on the older, moved to `wontfix`
|
|
"duplicate of N" last. The older issue never moves.
|
|
|
|
A second delivery of the event finds the kept judgement and finishes what is missing without judging again. A
|
|
judgement that fails leaves one note, and the event is not taken: after its fifth delivery the controller raises
|
|
`max-deliveries` on the module's consumer. Notes the duplicate check of ADR 0278 wrote as `duplicate-check` are
|
|
still read as that issue's verdict.
|
|
|
|
**Ready.** An issue is ready when it is not resolved or wontfix and every issue it depends on is wontfix, or
|
|
resolved with every pull request its `fixed-by` names (`<repository>#<number>`) delivered. The module consumes
|
|
`mesh-delivery.transition` and marks a pull request delivered on every issue naming it; at its own `moved` to
|
|
resolved it asks `seat:mesh-delivery.checks` once for what it has not heard. An issue made ready gains a note and
|
|
the event `ready`. `get` answers `waits-for`, `needed-by` and `ready`; `list` filters on `severity`, `needs` and
|
|
`ready` — an agent looking for work asks `severity=minor`, `needs=none`, `ready=true`. `set` changes severity,
|
|
needs and suggested owner as a person decides. `link` refuses a `depends-on` that would close a cycle.
|
|
|
|
`groom` triages every issue not resolved and not yet triaged, oldest first, against the older ones not resolved
|
|
and not found a duplicate in the same pass. It writes only the pass, in the state `grooming` (the last pass, one
|
|
key), each finding saying what applying it would do, and applies exactly that pass on `confirm`, each issue
|
|
checked again. One judgement runs at a time; the pass waits while a new issue's triage waits. A triage may take up
|
|
to two minutes, which the tool runner allows a handler while keeping its event alive (hq issue 387).
|
|
|
|
The new values are optional keys of an issue's one JSON value: an issue kept before reads as having none; the
|
|
key-value state has no schema to migrate.
|
|
|
|
## Whether the fix is delivered (hq ADR 0281)
|
|
|
|
For each pull request an issue's `fixed-by` names, the module keeps what `mesh-delivery.transition` last said —
|
|
state, why, merged and when — or asks `seat:mesh-delivery.checks` once (at its own `moved`) for one it has not
|
|
heard of. Nothing sets it by hand. `get` and every `list` row carry `delivery`, one line derived from it, worst
|
|
first: "fix not delivered: …", "held: …", "fix merged, not delivered: …", "fix not merged: …", "nothing heard from
|
|
the delivery of …", "delivered to every machine it should reach" (covered by a later merge says so).
|
|
|
|
Delivered is not resolved. When every fix of an issue not yet resolved is delivered, the issue gains a note and the
|
|
event `ready-to-verify`, once per set of fixes; it is resolved once its acceptance is proven live. A fix is named
|
|
while the issue stays `fixing`: `move` to the status it has changes what it holds and is refused when it changes
|
|
nothing.
|
|
|
|
**The fixes of an issue are its `fixed-by` and the pull requests linked to it** (link kind `pull-request`; hq issue
|
|
483): agents link a pull request while the issue is in fixing and give `fixed-by` at the resolve, so a delivery read
|
|
on `fixed-by` alone missed every fix being verified. Readiness still reads `fixed-by` alone, so a pull request linked
|
|
and abandoned holds no dependent back. A pull request closed without merging (`stopped`, and never merged) is **withdrawn**: not
|
|
a fix awaiting delivery, not delivered, not open; the line says "fix withdrawn: …" when it is the only one. Merged is
|
|
read from the delivery's `merged_as` or the pull request's own `merged`, never from the state, since `stopped` is
|
|
also what a closed pull request becomes. A pull request linked after its delivery moved hears no transition again: each
|
|
sweep asks mesh-delivery for at most five fixes never heard of, of issues not resolved.
|
|
|
|
The ready-to-verify note names each fix with when it was delivered, and the issue's worker; the event carries
|
|
`worker` and `delivered-at`. No channel of the tracker reaches a worker, so the note and the event are how it hears.
|
|
|
|
**Delivered, not resolved** (hq issue 483). An issue in fixing whose every fix is delivered carries
|
|
`delivered-not-resolved` on `get` and its `list` row. Past `delivered-not-resolved-after` (default `1h`) from the last
|
|
delivery, the sweep says it once as a warning on the operator's channel, key
|
|
`issue-tracker.delivered-not-resolved.<number>`, "issue N: fixed and delivered, not resolved; <worker> works on it",
|
|
cleared there when the issue leaves fixing or names a fix not delivered yet (at its `moved`, or the next sweep).
|
|
|
|
**Abandoned** (hq issue 483). An issue in diagnosing or fixing whose worker did nothing on it for
|
|
`worker-stale-after` (default `24h`) and that names no pull request still open (not merged, or never heard of)
|
|
carries `abandoned` on `get` and its `list` row, beside its `worker`. A move by someone else takes it over without
|
|
`take-over`'s reason, as any stale worker; the answer, the note and the `moved` event say it was abandoned
|
|
(`abandoned`).
|
|
|
|
Every five minutes the module looks for a fix merged and not delivered after `stuck-after` (default `2h`): it is
|
|
said once — a note on the issue and a warning on the operator's channel (`seat:operator-channel.notify`, key
|
|
`issue-tracker.fix-stuck.<number>`), cleared there when every fix of the issue is delivered. 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.
|
|
|
|
## 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
|
|
over the bus** (`records_status`, `records_list`, `records_read`, called as this module through the SDK's
|
|
`Ask`), at the commit the records module's checkout stands at, and writes each as an issue **at its own
|
|
number**: `record` is the folder, the title is the report's heading, the report is the text under it, and
|
|
`status`, `opened`, `located-in`, `fixed-by`, `amended-design`, `replay` and `replay-none` are the
|
|
frontmatter's, as written — the status one to one, no cycle rule applied, because the folder's status is
|
|
the snapshot hq kept. The issues and decision records the report names (`issue 155`, `ADR 0275`,
|
|
`04-ISSUES/203-…`, `02-DECISIONS/0019-…`) become `relates-to` and `decision` links.
|
|
|
|
It is a verb on the seat, callable by any agent, because it can do only this:
|
|
|
|
- **It only creates an issue that is not there** (`create` on the key, refused when the key exists) **or
|
|
fills the status of one the tracker holds without a status** — an issue opened with a folder before this
|
|
slice, whose folder kept its status; one whose folder hq does not hold at the commit becomes `open`.
|
|
- **It never overwrites.** An issue the tracker holds differently is reported as `differs`, naming the
|
|
fields, and left alone: the tracker is the truth. An issue it holds the same is `same`. So a second run
|
|
changes nothing and says so.
|
|
- **It never touches the counter**, and refuses the whole run when a folder is numbered past the counter.
|
|
A folder numbered at or past the setting `first-number` without an issue in the tracker is refused on its
|
|
own: a folder from the tracker's time carries a number the tracker gave.
|
|
- **It cannot forge an issue's history.** An issue it writes is `opened-by: import`, its `opened` the date
|
|
the report gave, and it carries `imported: {at, by, commit, from}` — when, who ran the import (the caller,
|
|
as the runtime proves it), the commit of hq and the document. Each is an
|
|
`imported` event. What it writes comes from hq's `main` as the records module holds it, which is reviewed
|
|
in pull requests.
|
|
- **What it keeps is bounded** as every verb's text is: the title 200 bytes, the report 64 KiB, one issue
|
|
252 KiB; a report that trips a credential's shape is refused. An entry of `located-in` or `fixed-by` hq
|
|
wrote is prose at times, so it is taken within a reason's bound (2000 bytes), not a line's.
|
|
- **An owner hq named that the registered list does not know is kept as written and marked**, in
|
|
`located-in-unverified` on the issue and `unverified-owners` in the answer, never refused: the list is
|
|
the setting's problem (hq issue 366), and a `move` that gives `located-in` anew checks every entry and
|
|
clears the mark.
|
|
- **With `dry-run`** it reads everything, writes nothing, and answers the same rows with `would-` on each
|
|
action. **With `commit`** it refuses a checkout standing elsewhere; it refuses a run during which the
|
|
checkout moved.
|
|
|
|
The answer is a row per folder — number, action (`create`, `fill`, `same`, `differs`, `refused`, with why),
|
|
status, title — the counts, the counts by status, what was odd (a title numbered otherwise than its
|
|
folder, a frontmatter key not imported, an `amended-design` that is no design document) and the unverified
|
|
owners. A call that outlives the tool runner's wait is still running: the import goes on, and the answer
|
|
is read back through the controller's `calls` verb by the call's id.
|
|
|
|
Before the module is rolled out, `mesh-issues dry-run <hq checkout> <settings.json>` at the terminal runs
|
|
the same dry run over a checkout on disk against an empty tracker, and prints the answer. It is not a way
|
|
to import: only the verb writes, and it reads the record over the bus.
|
|
|
|
**Every argument is read strictly.** One a verb does not take is refused, never dropped. Every field has a
|
|
size limit, a one-line field takes no control character, a folder's name is no path, and text shaped like
|
|
a credential (a private key, an API key, a forge or bus token, `password=…`) is refused: an issue is read by
|
|
every agent on the mesh. The shapes catch the ordinary mistake, not every secret.
|
|
|
|
## Numbers
|
|
|
|
One counter, the key `issue` of the state `counters`, advanced only by compare-and-set: the SDK's
|
|
`State(...).Increment` reads it and writes the next number only at the revision it read, so two openers —
|
|
in one instance or two — never take one number. A write another opener won is read and tried again, a
|
|
bounded number of times with a short random wait; past the bound the open is refused and takes no number.
|
|
|
|
- **A refused open takes no number**: an issue is checked before its number is taken.
|
|
- **A number is never handed out twice, and may be skipped.** A number taken and then not taken by the log —
|
|
the bus failing between the counter and the issue's first operation, or a full log — is spent, and the open
|
|
answers the failure (hq ADR 0300 §2). An append whose answer was lost is recognised as its own by the open's
|
|
id when tried again or read back, so it leaves no gap; when it cannot be confirmed either way, the answer says
|
|
the issue may have been written and to `get` that number before opening it again, never that nothing was
|
|
opened.
|
|
- **An issue is never overwritten.** Its first operation is appended at `expect` 0, refused when the log
|
|
already holds one for that number; if the counter ever hands out a number already kept, the open is refused
|
|
loudly, the number stays unused, and nothing is overwritten.
|
|
- **The counter starts once**, the first time a number is taken: at the setting `first-number`, or after
|
|
the highest issue already kept, whichever is higher, made only if it does not exist. The setting is never
|
|
read again, so a number never moves.
|
|
|
|
## Decision and research numbers
|
|
|
|
`issue-tracker.reserve {"kind": "decision"|"research", "for": "…"}` answers `{"kind": …, "number": N}` (hq
|
|
issue 424; the knowledge base asks it before it writes a record, ADR 0290 rule 5). Each kind has its own
|
|
counter beside `issue` in `counters` — keys `decision` and `research` — advanced the same way, so two
|
|
sessions writing a record at once never take one number.
|
|
|
|
- **A reserved number is spent forever**, whether or not its record ever lands; it is never handed out again.
|
|
Each is kept in the state `reservations` under `decision-0292` or `research-046` with who reserved it
|
|
(`by`, the caller as for every verb), when (`at`) and
|
|
`for`, and said as the event `mesh-issues.reserved`. A reservation whose write cannot be confirmed is
|
|
refused, and its number stays spent.
|
|
- **A refused reserve takes no number**: a kind other than `decision` or `research`, a `for` that is not one
|
|
line of plain text or looks like a secret, an unknown argument.
|
|
- **A counter starts once**, at the first reserve of its kind, at the highest of: the highest number of that
|
|
kind the knowledge base holds (`mesh-knowledge.knowledge_highest`, which counts every number spent there:
|
|
accepted, proposed, reserved or withdrawn; hq issue 488), the setting `decision-floor` or `research-floor`,
|
|
and the reservations kept. The first number handed out is one above. hq's folders are not read: the records
|
|
live in the knowledge base, and those folders empty when they leave hq (hq issue 426). When the knowledge base
|
|
does not answer (or holds none of the kind), the first reserve of a kind is refused and nothing is spent,
|
|
whatever the floor says: a floor raises the start, and never stands in for the knowledge base's answer.
|
|
- **Never at or below a number held**: each reserve asks the knowledge base again, and a counter that stands
|
|
below the highest number there is raised to it first, written only at the revision read. When the knowledge
|
|
base does not answer once the counter has started, the counter is used as it stands, and the answer's
|
|
`warning` says the number was not checked against the records held.
|
|
- **Open branches are the floor's job** while records are still written in hq: a number taken on an open
|
|
branch and not yet imported is covered by the floor. Before the first reserve of a kind, the operator raises
|
|
`decision-floor` or `research-floor` (the controller's settings verb) to the highest number on any open
|
|
branch of hq; once the counter has started, the floor is not read again.
|
|
|
|
## The log, the bucket and the events (hq ADR 0300)
|
|
|
|
**The record is the log `changes`** (declared in the manifest's `logs`, made by the controller, hq ADR 0297),
|
|
one key per issue by number. Every write — open, move, note, link, set, the triage, a delivery's word on a
|
|
fix, a warning said or cleared, the import — is one operation appended under the issue's number with what
|
|
changed, who acted and when, at the sequence of the last operation the issue was folded at
|
|
(`AppendAt`). Another operation in between refuses it: nothing is written, the log is folded again and the
|
|
change applied to that, a bounded number of times. A write the log refused writes nothing; only an open's
|
|
number, once taken, stays spent. An operation that begins an issue (`opened`, `imported`, `carried`) holds it
|
|
whole; every other one names the fields given a new value (`set`), the lists added to at their end (`add`:
|
|
a note is kept as itself, not as every note again) and the fields taken away (`unset`). The fold applies them
|
|
as written, so a new kind of operation needs nothing new in the fold.
|
|
|
|
**The bucket `issues` is the fold of the log**, each issue carrying `folded`, the sequence
|
|
of its last operation. It is written after the append, at the revision read; one whose write fails after the
|
|
log took the change is behind, and caught up at its next change (the stale append is refused and the log
|
|
folded) or at the next start. Agents and views watch it as before. It still keeps 8 values per key, so the bus
|
|
cannot drop the older values before the carry has read them; it goes to one value per key (ADR 0300 §3) in a
|
|
follow-up, once the carry has run with a read of those values.
|
|
|
|
**On start**, the tracker watches its own bucket, carries what the bucket holds and the log does not (below),
|
|
reads the whole log page by page, folds every issue whose last operation is newer than its `folded` — an
|
|
emptied bucket is rebuilt whole — and raises the issue counter to the highest number in the log where it is
|
|
below. Until then a `list` reads the bucket and a write carries the issue it changes first.
|
|
|
|
**The switch** (ADR 0300 §6) is the carry, run on every start and before any write of an issue not carried:
|
|
for every issue the bucket holds with no `folded`, each value the bucket still keeps of it, read through the
|
|
runtime's `mesh/state.history` (hq ADR 0307), is appended oldest first as a `carried` operation holding the
|
|
whole issue and the bucket's revision of that value, and the fold written. It resumes rather than restarts: a
|
|
kept value at or below the highest revision a carried operation holds, or one the tracker wrote itself (it has
|
|
`folded`), is known to the log, so an interrupted carry, or two instances carrying one issue at once, carry each
|
|
value once. Matched by revision, not content, because the same content may be kept twice. A value written beside
|
|
the log after the carry, by an instance from before the switch, is carried as one more operation and is never
|
|
written over by a fold. A deletion among the kept values is passed over and counted, since the tracker never
|
|
deletes an issue and every value after one holds the issue whole.
|
|
|
|
An issue that cannot be carried — the log refusing it, or a value this module cannot read — is a fault, named
|
|
with its reason in the start line; the others are carried and the start finishes. That issue stays in the
|
|
bucket as it was, read and listed as before, and every write to it is refused with the same reason until it
|
|
can be carried, so no operation reaches the log before its carry. One issue is kept in at most 252 KiB, so that
|
|
the operation holding it whole fits one entry of the log (256 KiB). An entry of the log that cannot be folded
|
|
faults its issue on start: nothing folded past it is written, and its bucket value is left as it is.
|
|
|
|
**In memory** the tracker holds every folded issue, kept current by the watch and its own writes, and a
|
|
full-text index of title, report and notes, ranked by BM25 (title words weigh three), rebuilt on every start.
|
|
`list` answers from memory, with `search` ranked best first, and `before` paging the newest-first list past
|
|
the 500 rows one answer holds. The index is the module's own: a few thousand issues need a hundred lines, not a
|
|
library of dozens of modules.
|
|
|
|
The other states: `counters`, one value per key (`issue`, `decision`, `research`); `grooming`, the backlog's
|
|
pass; `reservations`, one key per reserved number. None expires. One issue is kept in at most 252 KiB; a note
|
|
that would pass it is refused.
|
|
|
|
**The events announce; the log is the audit trail.** Every change is still an event: `mesh-issues.opened`,
|
|
`.moved`, `.noted`, `.linked`, `.imported`, `.reserved`, each with the number, what changed, who changed it and
|
|
when. A change whose event the bus did not take is kept, and its answer says the event was not said
|
|
(`announced: false`).
|
|
|
|
## Who acted
|
|
|
|
ADR 0275 §5 records the caller from the bus credential, never from an argument. **Who acted is the bus user
|
|
that called** (hq issue 365): a call on a tool's caller-named subject carries the caller's bus user as its last
|
|
token, the bus lets each user publish there with its own name alone, and the tool runner hands the module that
|
|
user from the subject the call arrived on (mesh-sdk `stdio.CallerOf`) — `shanks.node-tools` for an agent on
|
|
that machine's console, `person.<name>` for a person's credential. A call on the subject that names no caller
|
|
(served beside it for one release, hq issue 464), or through a runtime from before issue 365, is recorded as
|
|
by `unproven`. No verb takes an argument naming a caller, and none can be given one. The caller is only as sound
|
|
as the credential, which ADR 0266 keeps agents from reading (hq issue 333).
|
|
|
|
## Settings
|
|
|
|
`duplicate-check` (`on`; `off` stops the triage of new issues), `judge-model` (`sonnet`; `haiku` or `opus`) and
|
|
`forge-owner` (the forge's owner of the repositories `fixed-by` names, for asking a delivery) steer the triage;
|
|
`stuck-after` (`2h`) is how long a merged fix may take to be delivered before it is said;
|
|
`delivered-not-resolved-after` (`1h`) how long an issue may stay in fixing once every fix is delivered before it is
|
|
said (hq issue 483).
|
|
|
|
```
|
|
{
|
|
"first-number": 365,
|
|
"owners": ["hq", "mesh-catalog", "mesh-catalog modules/nats", "mesh-controller", …]
|
|
}
|
|
```
|
|
|
|
- `first-number` — the number the first issue gets: the one after the highest issue number on hq's main
|
|
and every open branch at the moment the module is switched on. Read once for the counter; the import
|
|
reads it as the boundary between the folders hq numbered before the tracker and the numbers the tracker
|
|
gave.
|
|
- `decision-floor`, `research-floor` — the highest decision and research numbers taken where the tracker cannot
|
|
read, such as an open branch of hq (293 and 45 when this was written: 0293 on an open branch, 045 on main).
|
|
Read once, when that kind's counter starts; see *Decision and research numbers*.
|
|
- `worker-stale-after` — how long an issue's worker stays current with nothing done on the issue (hq ADR 0284),
|
|
as a duration; `24h` when empty.
|
|
- `owners` — the registered list `located-in` may name: repositories, and modules as
|
|
`mesh-catalog modules/<module>`. An entry of `located-in` is an owner, or an owner followed by a space or a
|
|
slash and where in it (`mesh-controller internal/broker`, `mesh-catalog modules/nats/module.json`). A module
|
|
must itself be registered: `mesh-catalog modules/<module>` is never taken as a place in `mesh-catalog`. It starts with the mesh's repositories and the modules
|
|
the catalogue held when this module was written; a module added since is added here through the
|
|
controller's settings verb.
|
|
|
|
## Tests
|
|
|
|
`go test ./...` in this directory. The acceptance — an agent opens an issue and gets the next number; two
|
|
agents opening at the same moment never get the same one — is
|
|
`TestFiftyOpensAtOnceFromTwoInstancesGetFiftyDistinctConsecutiveNumbers`: a JetStream server linked into
|
|
the test, two instances of this bundle (the test binary started again) speaking to a runtime played by the
|
|
test against the buckets the manifest declares, fifty opens at once, fifty distinct numbers from the first
|
|
in a row. It counts the writes lost to another opener, so it fails when the openers never collided. With
|
|
the counter written without its revision check, it fails.
|
|
|
|
`reserve`'s acceptance — sessions reserving at the same moment never get one number, and the first is above
|
|
what the knowledge base holds — is `TestFortyReservationsAtOnceFromTwoInstancesGetFortyDistinctConsecutiveNumbers`
|
|
on the same bus, with the knowledge base played by the test, and the tests in `reserve_test.go`: the start above
|
|
the knowledge base, the floor and the reservations kept, a counter behind the knowledge base raised, a refused
|
|
reserve spending nothing, the first reserve refused while the knowledge base does not answer, even with a floor
|
|
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.
|
|
|
|
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
|
|
number with the counter untouched, a second run changing nothing, an issue the tracker holds differently
|
|
left alone, a folder-backed issue filled once, a folder past the counter or past the first number refused,
|
|
a dry run writing nothing, and a report that cannot be read refused alone with why.
|
|
|
|
The log (hq ADR 0300) is tested in `log_test.go` over a log kept in the test with the runtime's semantics
|
|
(`expect`, `ErrChanged`): a write whose append is refused changing nothing, an operation in between not lost, an
|
|
open refused at validation taking no number, an append failing after the number spending it and answering the
|
|
failure, an emptied bucket restored exactly by the fold on start, a bucket behind its log catching up, the
|
|
counter raised to the log, each write saying its event beside its one operation, `before` paging 530 issues
|
|
without a gap or a repeat, a ranked search with the index rebuilt on start and kept current by the watch, and
|
|
the carry carrying each value kept, oldest first, once, passing over a deletion among them. Over the bus, a
|
|
write to an issue the bucket kept before the switch carries its three kept values first, read through the
|
|
runtime's history. Over the bus, the stream the controller makes holds one
|
|
operation per change of `TestAnIssueIsOpenedNotedLinkedMovedAndListedOverTheBus`.
|